LCuter
2018-09-15 13:41:06
贪心,就是在对问题求解时,总是采用当前最好的选择。但是贪心算法不一定正确,一是问题不适用贪心,二是贪心思路不正确。在赛场上,一般没时间证明除非神仙,只需试试能不能举出反例(说不定可以拿来骗分)。贪心有难有易,同时有可能结合别的算法一起呈现,比如二分判定答案可能就会用到贪心。
接下来,我会结合几道例题,提炼出一些比较有用的贪心思路
通过样例推结论
某些题通过样例及其说明可以猜到正解。但是有些毒瘤题样例会使错误贪心表面上正确,还需多多证明
多刷题
动态规划和贪心正确性都基于问题的最优子结构性。但是有部分问题贪心不能用而动态规划能用(走方格),也有部分问题动态规划明显没有贪心简单。
一个旅行家想驾驶汽车以最少的费用从一个城市到另一个城市(假设出发时油箱是空的)。给定两个城市之间的距离
先骗个分,判无解。无解的情况就是开到一半没油了。枚举每个加油站,如果加满油还是开不到下一个加油站就是无解,无解可以在下文的正解思路中一起判。
开始考虑正解。这一次旅行,最关键的就是每个加油站和终点,所以我们从起点加油站开始模拟,直到终点。
我们梳理一下思路
这两个有什么用呢?从这两条信息可以推导出,最优解必须满足加的油最好刚好用完,因为开完路程的耗油量是固定的,所以加的油如果没用完就会浪费。我们得到
现在就更方便了,要想让花费最少,就要尽量加便宜的油。我们用贪心思想,推导出接下来的模拟需要满足以下两个条件
我们挑选任意一个加油站,开始模拟(这是在讲思路,真正做题不是这样做的)。可以分两类讨论:
第一类比较容易,肯定是先使油能够开到离自己最近且比当前加油站便宜的油站,我们设红色是当前加油站加的油,橙色是离自己最近且比当前加油站便宜的加油站加的油,见下图:
很明显,橙色段比红色段便宜,所以上面的比下面的便宜,那么正确性便体现出来了。接着我们做完一系列的更新,就把当前位置调整至那个加油站
第二类稍麻烦。如果可以直接开到终点,那就直接开,否则类似上面那张图,会亏。如果不能直接开到终点,我们就加满。首先因为不能直接开到终点,所以这不会造成任何浪费。还是上图,橙色表示当前加油站的油,红色表示当前加油站所能开到的其它加油站的油,如下:
橙色段比红色段便宜,所以按下面的方法开省钱。加满之后,开到范围内最便宜的车站,再作下一步决定。
至此,我们发现,这个问题的解题思路已经被我们解决了
设有一个二元组
这道题要用到高精度,这里不讨论。
我们从比较小的情况分析
排列情况如上
易得
另一种排列如下
易得
比较明显的关系有:
若要
所以
所以
[HAOI]糖果传递
即推出答案表达式贪心求得最优解
这道题好像洛谷上没有??
长
为方便后文讲解,现设第
乍一看,这道题像是覆盖一个区间,但是它是用圆覆盖长方形,这让人有点犯难。
但是,我们看下图:
(为方便只绘制了几个)
这个图形是一个以长方形两宽中点连线段所在的直线为对称轴的轴对称图形(这表述对得起我敬爱的语文数学老师)。所以我们可以只看上部分。再接着看,我们称一个圆真正浇灌范围是一个不需要其它圆再覆盖的部分。
再接着看,我们称一个圆真正浇灌范围是一个不需要其它圆再覆盖的部分。如上图,黑色部分是圆没有覆盖到的地方,但是这周围两个圆明明最左/最右端点已经超过了啊,可是圆就是这样,所以这一块(包括它们正下方圆有覆盖的地方)不属于圆的真正浇灌范围。那么一个圆的真正浇灌范围是哪里呢?
如上图最右边的圆,它的真正浇灌范围用黑色块表示,容易发现,这是个长方形,而且长方形的两个端点正是圆与草坪上方的两个交点。上图中有两个圆,并没有与草坪上方有两个交点,也就是说这些圆真正浇灌范围为0,下面的讨论中不考虑这一类圆,它们的共同特征是
接下来就不放图了,因为如果你把圆换成长方形,就会发现它等价于有
seg[i].l=a[i]-sqrt(r[i]*r[i]-(W/2)*(W/2));
seg[i].r=a[i]+sqrt(r[i]*r[i]-(W/2)*(W/2));
自行理解吧
区间覆盖问题怎么求呢?区间覆盖的形式化描述是这样的:给定
做法是将区间以左端点坐标为关键字从小到大排序。一开始选点
小明有
题目条件限制太多,我们先考虑钓鱼怎么钓。显然,每次求能钓到最多的鱼塘钓即可,具体写个堆。但是我们添加了走路的过程,就头痛了。
这次我们只考虑走的过程,即走的路最少。只要不走回头路不就OK了?
结合起来:从头走到尾,选最多的钓。但是我们很快反应过来:假设第一次钓最多的鱼塘在后面,但是第二次钓最多的鱼塘在前面,这不就违反上面的思路了吗?别慌,在鱼塘里钓鱼并不会影响其它鱼塘的鱼——也就是说钓鱼的次序调换并不会影响最后掉到的鱼的总量。我们在每次选择最大值时仍按原方案,但是计算总路程时重新给次序排成最优方案即可,在这里我们认为最短距离就是总路程。
那么总路程是多少呢?是从头到尾吗?如果限定时间内走不到怎么办呢?是从头到能走到的最远的鱼塘吗?如果最优方案并没有到那个鱼塘怎么办呢?既然不能明确总路程,那么我们就枚举每个鱼塘,对每一次枚举求局部最优解,最后选最优解即可,当然,只需枚举到最远能在限定时间内到达的鱼塘即可。
还有一个小技巧,可以把五秒作为一个时间单位来计算。
这类问题可以归结于动态求最值的问题,可以用堆解决问题
对于某些不确定的值,采用枚举求最优解的方法(以前看到过一道差分约束题因为变量在不等式右边,所以把变量视作定量枚举求最优)
题目限制条件多的,可以拆分来看
合并果子
特别简单的一道题
贪心是一种思想,而非算法,所以很难抽象地去讲解,只能通过这种结合例题的方法去讲解。由于贪心不一定正确,在想出一种思路后最好找找反例或者自己证明。贪心在图论中也有自己的用武之地(Prim,Dijstra,Kruskal)