[NOIP2004 提高组]合并果子(贪心,优先队列,小根堆一口气学会)

本文主要是介绍[NOIP2004 提高组]合并果子(贪心,优先队列,小根堆一口气学会),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在这里插入图片描述
题目链接洛谷P1090

题意

意思就是给你一堆数(比如1 2 3)
让你加到只剩一个数(1+2+3=6)
每次加的代价是加出来的数(1+2=3 , 代价是3 ; 3+3=6 , 代价是6 ; 6+3为总代价)
要求最小代价(引入一种思想:贪心)

贪心

贪心算法,其实根本不用讲,它的核心思路就是求出局部最优解,走一步算一步,每一步都选当前的最优解,根本不从整体上考虑,然后把所有局部解求出来合成整体解。
举个例子,小红邀请小明和小军到小红家玩,但是小红家比较小,只能容纳两人在这里插入图片描述
从图上可以看出,小军无论怎么走都要走2km,然而小明有两条路可以走,一条是1km,一条是3km,如果你是小明,你会怎么走呢,很明显,走1km这条路,就可以愉快地跟小红一起玩耍了。
这就是贪心,选择局部的最优解,然后凑成整体的最优解,如果还不能理解
在这里插入图片描述
那么这次你会作何选择呢,当然是一直往前,而不是弯着走,但是你思考的时候,其实有把它们分开看,也就是,小明和小红家之间有一个必经中转点,所以要到达小红家就得先到必经中转点,到达必经中转点的最优路径是1,而必经中转点到小红家的最优路径也是1,所以这么走最快
你会发现,最终的答案是由局部得来的,而且依赖于前面的选择(不理解可以想想在小明到必经中转点那条2km的路径上再加一个点,然后把这个新点到达必经中转点的路径删掉,这样就到不了小红家了,所以它依赖于前面的选择),这就是贪心

回归题目

讲了这么多,贪心应该懂了吧,现在回归题目,怎么求最小代价呢,那就分成局部问题吧,局部问题就是合成两堆果子的最小代价对吧,而合成两堆果子的最小代价很显然求,就是把这一大堆果子里把最小的两堆果子合在一起吧?
那解法就昭然若揭了,我们把这堆果子放进一个数据结构里,然后对它从小到大排序,每次取出最小的两个出来,加起来,放到最后,然后再排序一次,让这个新合成的果子找到自己的位置,循环往复,直到只有一堆,合成的过程记录一下代价就好了。

但是每次都排序这样的时间复杂度很大,即使是STL里的sort,每次排序也要 O(nlogn) 的时间,那么有什么数据结构能很快地完成排序这个重要的任务呢

堆是一种特殊的二叉树,它分为小根堆,大根堆
树之所以叫树呢,是因为它长这样
在这里插入图片描述
你也可以这么看它
在这里插入图片描述
第一个"爸爸"结点呢,就叫根结点,每个结点有几个儿子就叫几叉树,但是按照爸爸的数值比儿子小这种存储方式的树,叫小根堆爸爸存的数值比儿子大这种存储方式的树,叫做大根堆
也就是说,在大根堆里,最大的数,是根节点,在小根堆里,最小的数是根节点
我们一般用数组来模拟树,比如 tree[100] tree[1]为根结点,tree[2]和tree[3]为1的子结点,也就是,一个结点的儿子在数组中的位置为i*2i*2+1这样就不会有重复,而且能很快查询父亲或者儿子了

用小根堆的代码如下,注解很多,如果不要注解,可以往下翻

有注解版

#include<bits/stdc++.h>
#define op <		//将此处的<号改成>号即为大根堆 
using namespace std; 
int heap[1000086]/*堆*/, size/*堆的长度*/;
void swim(int n)
{//接下来这段要熟悉for循环的执行顺序//for ( 循环开始时执行且只执行一次 ; 1  ; 3 ) {  2  } for (int i=n ; i>1/*不是根节点就上浮*/&&heap[i] op heap[i / 2]/*跟父结点比较*/ ; i /= 2)swap(heap[i], heap[i / 2]);
}//将子节点与父节点进行比较,不断上浮 
int son(int n)//如果左儿子比右儿子小,返回左儿子,不然返回右儿子 
{//此处的处理有点巧妙,本来是要比较左儿子与右儿子的大小//但是因为n的左儿子是2*n,右儿子是2*n+1//所以用一个判断式来代表这个1存不存在//下面的2*n是左右儿子的公有部分 //如果你觉得这样很复杂,可以重新写一个思路一样的更简单的,但是更长的代码 return n

这篇关于[NOIP2004 提高组]合并果子(贪心,优先队列,小根堆一口气学会)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/498379

相关文章

Redis延迟队列的实现示例

《Redis延迟队列的实现示例》Redis延迟队列是一种使用Redis实现的消息队列,本文主要介绍了Redis延迟队列的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习... 目录一、什么是 Redis 延迟队列二、实现原理三、Java 代码示例四、注意事项五、使用 Redi

基于C#实现PDF文件合并工具

《基于C#实现PDF文件合并工具》这篇文章主要为大家详细介绍了如何基于C#实现一个简单的PDF文件合并工具,文中的示例代码简洁易懂,有需要的小伙伴可以跟随小编一起学习一下... 界面主要用于发票PDF文件的合并。经常出差要报销的很有用。代码using System;using System.Col

Python视频剪辑合并操作的实现示例

《Python视频剪辑合并操作的实现示例》很多人在创作视频时都需要进行剪辑,本文主要介绍了Python视频剪辑合并操作的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习... 目录介绍安装FFmpegWindowsMACOS安装MoviePy剪切视频合并视频转换视频结论介绍

不删数据还能合并磁盘? 让电脑C盘D盘合并并保留数据的技巧

《不删数据还能合并磁盘?让电脑C盘D盘合并并保留数据的技巧》在Windows操作系统中,合并C盘和D盘是一个相对复杂的任务,尤其是当你不希望删除其中的数据时,幸运的是,有几种方法可以实现这一目标且在... 在电脑生产时,制造商常为C盘分配较小的磁盘空间,以确保软件在运行过程中不会出现磁盘空间不足的问题。但在

在C#中合并和解析相对路径方式

《在C#中合并和解析相对路径方式》Path类提供了几个用于操作文件路径的静态方法,其中包括Combine方法和GetFullPath方法,Combine方法将两个路径合并在一起,但不会解析包含相对元素... 目录C#合并和解析相对路径System.IO.Path类幸运的是总结C#合并和解析相对路径对于 C

如何提高Redis服务器的最大打开文件数限制

《如何提高Redis服务器的最大打开文件数限制》文章讨论了如何提高Redis服务器的最大打开文件数限制,以支持高并发服务,本文给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧... 目录如何提高Redis服务器的最大打开文件数限制问题诊断解决步骤1. 修改系统级别的限制2. 为Redis进程特别设置限制

hdu1180(广搜+优先队列)

此题要求最少到达目标点T的最短时间,所以我选择了广度优先搜索,并且要用到优先队列。 另外此题注意点较多,比如说可以在某个点停留,我wa了好多两次,就是因为忽略了这一点,然后参考了大神的思想,然后经过反复修改才AC的 这是我的代码 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<

hdu2241(二分+合并数组)

题意:判断是否存在a+b+c = x,a,b,c分别属于集合A,B,C 如果用暴力会超时,所以这里用到了数组合并,将b,c数组合并成d,d数组存的是b,c数组元素的和,然后对d数组进行二分就可以了 代码如下(附注释): #include<iostream>#include<algorithm>#include<cstring>#include<stack>#include<que

usaco 1.3 Barn Repair(贪心)

思路:用上M块木板时有 M-1 个间隙。目标是让总间隙最大。将相邻两个有牛的牛棚之间间隔的牛棚数排序,选取最大的M-1个作为间隙,其余地方用木板盖住。 做法: 1.若,板(M) 的数目大于或等于 牛棚中有牛的数目(C),则 目测 给每个牛牛发一个板就为最小的需求~ 2.否则,先对 牛牛们的门牌号排序,然后 用一个数组 blank[ ] 记录两门牌号之间的距离,然后 用数组 an

day-51 合并零之间的节点

思路 直接遍历链表即可,遇到val=0跳过,val非零则加在一起,最后返回即可 解题过程 返回链表可以有头结点,方便插入,返回head.next Code /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}*