贪心算法和动态规划的不同之处
在动态规划方法中每个步骤都要进行一次选择,但选择通常依赖于子问题的解。因此,我们通常以一种自底向上的方式求解动态规划问题,先求解较小的子问题,然后是较大的子问题。我们也可以自顶向下的求解,但需要备忘机制,当然,即使算法是自顶向下进行计算,我们仍然需要的先求解子问题在进行选择。
在贪心算法中,我们总是做出当时看来最佳的选择然后求解生下的唯一的子问题。贪心算法进行选择时可能依赖之前做出的选择但不依赖任何将来的选择或者是子问题的解。因此,与动态规划先求解子问题才能进行第一次选择不同,贪心算法在进行第一次选择之前不求解任何的子问题。
贪心算法在每一步都做出当时看起来最佳的选择,也就是说它总是做出局部最优的选择,希望这样的选择能导致全局最优,但是并不能保证得到最优解。最小生成树算法、单源最短路径的Dijkstra算法都是贪心算法策略设计的算法。
活动选择问题。每个任务都有一个开始时间Si和一个结束时间Fi,其中对单个的活动来说,它的结束时间要大于开始时间。如果两个活动ai和aj满足[si,fi],[sj,fj]不重叠则说明它们是兼容的。也就是说si>=fj或者是sj>=fi,则说明这两个活动是兼容的。下面这些活动已经按照结束时间的先后顺讯进行排序。
i 1 2 3 4 5 6 7 8 9 10 11
si 1 3 0 5 3 5 6 8 8 2 12
fi 4 5 6 7 9 9 10 11 12 14 16
选择一个最大兼容活动集,而对于每一步所要做出的贪心选择就是选择最早结束的活动,结束越早的活动说明结束这个活动之后的资源越能尽可能让更多的活动所利用,才能达到我们的目标使得活动兼容集尽可能额大。假设我们设置一个虚拟活动为a0,他的开始时间和结束时间都为0,那么在这个活动结束后最先开始的活动ai会被考虑进来,同理说,在活动ai结束后最先开始的活动也应该考虑,这样层层迭代就能得到最大兼容活动集,只有在某一个最先活动结束后最先开始的活动才能最先结束并且把资源空出来。
粘代码~~~
package Greedy;
import java.util.ArrayList;
public class Activity_Selector {
//递归贪心算法
public static String recursive_activity_Selector(int[] s,int[] f,int k,int n){
int m=k+1;//所有的活动结束时间已经从小到大进行排序
//在当前活动后的活动中找到时间上吻合的活动,也就是在当前活动结束后开始的活动,才能满足兼容的性质
while(m<=n&&s[m]<f[k]){
m++;
}
//找到第一个和活动k满足兼容性质的活动,找到后加入本集合,重复此问题
if(m<=n){
/*activityList.add("a"+m);*/
if(recursive_activity_Selector(s,f,m,n)!=""){
return "a"+m+"+"+recursive_activity_Selector(s,f,m,n);
}
return "a"+m;
}
return "";
}
//迭代贪心算法
public static String greedy_activity_Selector(int[] s,int[] f){
//采用非递归的形式就可以
int length = f.length;
int k=1;
String str ="a"+k;
for(int i=2;i<length;i++){
if(s[i]>=f[k]){
str+="a"+i;
k=i;
}
}
return str;
}
public static void main(String[] args) {
int[] s = {0,1,3,0,5,3,5,6,8,8,2,12};
int[] f = {0,4,5,6,7,9,9,10,11,12,14,16};
/*System.out.print(recursive_activity_Selector(s,f,0,11));*/
System.out.print(greedy_activity_Selector(s,f));
}
}