1、贪心思想:贪心算法总是作出在当前看来最好的选择,也就是说贪心算法并不从整体最优考虑,它所作出的选择只是在某种意义上的局部最优选择。虽然贪心算法不能对所有问题都得到整体最优解,但对许多问题它能产生整体最优解。在一些情况下,即使贪心算法不能得到整体最优解,其最终结果却是最优解的很好近似
2、基本要素:
1)贪心选择性质:只所求问题的整体最优解可以通过一系列的局部最优选择,即贪心选择达到。
2)最优子结构性质:当一个问题的最优解包含其子问题的最优解时,称其有最优子结构性质。
活动安排问题:
活动安排问题就是要在所给的活动集合中选出最大的相容活动子集合,是可以用贪心算法有效求解的很好例子。该问题要求高效地安排一系列争用某一公共资源的活动。贪心算法提供了一个简单、漂亮的方法使得尽可能多的活动能兼容地使用公共资源。
1、问题描述
设有n个活动的集合 E={1,2,…,n},其中每个活动都要求使用同一资源,如演讲会场等,而在同一时间内只有一个活动能使用这一资源。每个活动i都有一个要求使用该资源的起始时间和一个结束时间,且 < 。如果选择了活动i,则它在半开时间区间[, )内占用资源。若区间 [, ) 与区间 [, ) 不相交,则称活动 i 与活动 j 是相容的。也就是说,当 ≥ 或 ≥ 时,活动 i 与活动 j 相容。
2、贪心策略
使得活动的时间间隔最大化,可以使安排的活动达到最多,即先安排结束时间最早的活动,可以使得剩余的时间最大化,就可以安排更多的活动了。
3、算法步骤
第一步,将所有的活动按照结束时间从小到大排列;
第二步,扫描所有活动的开始时间与结束时间,若扫描到的活动i的开始时间s[i] 小于最近安排的活动j的结束时间f[j] ,则不安排活动i,否则选择活动i作安排。即比较:
4、 greedySelector 算法
下面给出的解活动安排问题的贪心算法greedySelector,各活动的起始时间和结束时间存储于数组s和f中且按结束时间的非减序 排列。
public static int greedySelector(int[] s, int[] f, boolean[]a){
int n=s.length-1;
a[1]=true; //第一个活动已安排
int j=1; //当前刚刚安排的活动
int count=1; //记录所安排的活动
for (int i=2;i<=n;i++) { //循环扫描活动数组 a[]
if (s[i]>=f[j]) { //第i个活动的开始时间与第j个获得的结束时间比较
a[i]=true; //表示第i个活动被安排
j=i;
count++;
}
else a[i]=false; //条件不成立,第i个活动不被安排
}
return count;
}
5、活动安排满足贪心选择
贪心选择性质:已知E={1,2,...,n} 为所给活动的集合(已排序)
证明:活动安排中有一个包含贪心选择的最优解(先给出最优解,在改造最优解,最后证明)
设:是该问题的一个最优解,且A也是排好序的,对A中的第一个活动k,如A={k,k+i,...,k+j},则有活动的开始时间集合S={ s[k],s[k+i],...,s[k+j] },结束时间集合F={ f[k],f[k+i],...,f[k+j] }。 当k=1时,A即为所求;当k!+1时,设B = A-{k}U{1} ={1,k+i,...,k+j},即B为所求;综上,由于f[1] ≤ f[k] ≤ f[k+i],所以活动1与活动k+i相容,且 |B|的个数 = |A|的个数。