贪心算法

贪心算法


贪心算法的基本思路:

从问题的某一个初始解出发逐步逼近给定的目标,以尽可能快的地求得更好的解。当达到算法中的某一步不能再继续前进时,算法停止。

该算法存在问题:

1. 不能保证求得的最后解是最佳的;

2. 不能用来求最大或最小解问题;

3. 只能求满足某些约束条件的可行解的范围。

实现该算法的过程:

从问题的某一初始解出发;

while 能朝给定总目标前进一步 do

    求出可行解的一个解元素;

由所有解元素组合成问题的一个可行解;

 

用背包问题来介绍贪心算法:

背包问题:有一个背包,背包容量是M=150。有7个物品,物品可以分割成任意大小。要求尽可能让装入背包中的物品总价值最大,但不能超过总容量。

物品 A  B  C D E F G

重量 35  30  60  50  40  10  25  

价值  10  40  30 50  35  40  30 

分析如下

目标函数: ∑pi最大

约束条件是装入的物品总重量不超过背包容量:∑wi<=M( M=150)


几种常见的贪心算法

1.线段覆盖(lines cover

 题目大意:在一维空间中告诉你N条线段的起始坐标与终止坐标,要求求出这些线段一共覆盖了多大的长度。

解题思路:将线段按其坐标进行排序(排序的具体方法:按起始坐标排,起始坐标相同的按终止坐标排,都是小在前大在后),使之依次递增,并按顺序分别编号为X(i),X(i).a代表其起始坐标,X(i).b代表其终止坐标。

然后按排好的顺序依次处理:定义一个变量last记录考虑到当前线段之时被线段覆盖的最大的坐标值,再定义一个变量length记录当前线段覆盖的长度。对于后面的线段,我们把它看成由两个部分组成,即把它分成last之前的线段和last之后的线段。(如果线段全部处在last之后,其last之前的部分不存在。)由于我们排过序,我们可以肯定当前考虑的线段X(i)其处在last之前的部分不会对length造成影响(因为X(i-1).b=lastX(i).a>=X(i-1).a,X(i)last之前的部分所处位置肯定被线段X(i-1)覆盖过),所以会对length产生影响的即是X(i)处在last之后的部分。

所以我们可以依次对每条线段做如下处理:(初始化length为零,last为负无穷)

length+=X(i).b-last      (X(i).a<=last 且 X(i).b>=last)

length+=X(i).b-X(i).a    (X(i).a>last)

last=X(i).b;

最后length就为我们所需要的答案。

 

2.最优数对(best pair

题目大意:按递增的顺序告诉你N个正整数和一个实数P,要求求出求出该数列中的比例最接近P的两个数(保证绝对没有两个数使得其比值为P)。

解题思路:定义两个指针ij,先初始化i=j=1,然后进行如下操作:

       当code[j]/code[i]>p时,incj);

       当code[j]/code[i]<p时,inci)。

 记录其中产生的最优值即为答案。

 

3.连续数之和最大值(max sum

 题目大意:给出一个长度为N的数列(数列中至少有一个正数),要求求出其中的连续数之和的最大值。(也可以加入ab来限制连续数的长度不小于a且不大于b)。

解题思路:

先说不加限制的那种,定义一个统计变量tot,然后用循环进行如下操作:inctotitem)其中如果出现tot<0的情况,则将tot赋值为0。在循环过程之中tot出现的最大值即为答案。

如果加入了限制条件的话,问题就变得难一些了。为此我们先定义数组sum[i]来表示code[1]code[i]之和(这样的话code[a]~code[b]的和我们就可以用sum[b]-sum[a-1]来表示了)。再维护一个数组hash[i]来表示满足条件的sum[a-1]的下标,并使之按递增顺序排列,这样当前以第i的数为终止的数列的最大值肯定就是sum[i]-sum[hash[1]]

 现在我们来讨论hash数组之中的数据需要满足的条件和如何维护的具体问题:

当考虑到以第i个数为结尾时,hash[i]所表示的下标需要满足的第一个条件就是题目规定的长度限制,我们需要实时的加入满足长度规定的下标,删除不符合要求的下标。其次,与不加限制条件时相同,若sum[i]-sum[hash[1]]的值小于零,则清空数组hash

维护时可以这样,当考虑到第i个数时,我们就将下标i-a+1加入到hash中,因为hash中原来已经排好序,因此我们我们可以用插入排序来维护hash的递增性,然后我们考察hash[1],若hash[1]<i-b+1,则证明其已超出长度限制,我们就将其删除,接着再考虑更新后的hash[1],如此重复直至找到一个满足条件的hash[1]为止。

我们可以用链表来表示hash,这样就可以减少数据加入和删除时频繁数据移动的时间消耗。记录下sum[i]-sum[hash[1]]的最大值即为答案。


贪心算法的基本思想是找出整体当中每个小的局部的最优解,并且将所有的这些局部最优解合起来形成整体上的一个最优解。因此能够使用贪心算法的问题必须满足下面的两个性质:
1.整体的最优解可以通过局部的最优解来求出;
2.一个整体能够被分为多个局部,并且这些局部都能够求出最优解。使用贪心算法当中的两个典型问题是活动安排问题和背包问题。

在对问题求解时,总是作出在当前看来是最好的选择。也就是说,不从整体上加以考虑,它所作出的仅仅是在某种意义上的局部最优解(是否是全局最优,需要证明)。
特别注意: 若要用贪心算法求解某问题的整体最优解,必须首先证明贪心思想在该问题的应用结果就是最优解!!

以经典的活动安排为例:
1、若A是E的最优解,那么E-A 也是问题的最优解,在余下的问题里,继续拿最早结束的;
2、拿可以开始的最早结束。(所以要按结束时间排序一次,然后把可以开始的选择上,然后继续向后推)

贪心子结构是独立的(往往用标志判断而已),不同于动态规划(后面每一边的计算要用到前一步的值,另外开辟空间来保存)
贪心算法的基本步骤 :
1、从问题的某个初始解出发。
2、采用循环语句,当可以向求解目标前进一步时,就根据局部最优策略,得到一个部分解,缩小问题的范围或规模。
3、将所有部分解综合起来,得到问题的最终解。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值