贪心算法总是作出在当前看来最好的选择。也就是说贪心算法并不从整体最优考虑,它所作出的选择只是在某种意义上的局部最优选择。当然,希望贪心算法得到的最终结果也是整体最优的。虽然贪心算法不能对所有问题都得到整体最优解,但对许多问题它能产生整体最优解,如之前的Dijkstra算法,Prim算法,Kruskal算法。如果不要求绝对最佳答案,那么有时候我们使用简单的贪婪算法生成近似的答案.
贪心与动态规划
贪心算法和动态规划都需求最优子结构,但是贪心算法是自顶向下方式进行,就是每一步,根据策略得到一个当前最优解。传递到下一步,从而保证每一步都是选择当前最优的。最后得到结果.每一步的最优解都依赖上一部的最优解.你只考虑之前已做出的选择
而动态规划通常自底向上解各种子问题,每一步,根据策略得到一个更小规模的问题。最后解决最小规模的问题。得到整个问题最优解.全局最优解中一定包含某个局部最优解,但不一定包含前一个局部最优解.你考虑的都是以后的子问题
经典的还是背包问题,之前的01背包问题我们采用动态规划解决而不能用贪心.但是如果改成部分背包问题呢:
假如有三件物品,背包可装50磅的物品,物品1重10磅,价值60元;物品2重20磅,价值100元;物品3重30磅,价值120元。你可以选择带走每个物品的全部或一部分,求如何选择可以使背包所装的价值最大?
注意到不同点是我们可以选择带走一部分,所以使用贪心算法十分自然地想到,先算含金量啊,先把含金量最高的都带完,再带含金量其次的…很容易得到解,带走一件1,一件2,2/3件3…比较简单代码不写.
活动安排问题
设有n个活动的集合E = {1,2,…,n},其中每个活动都要求使用同一资源,如演讲会场等,而在同一时间内只有一个活动能使用这一资源。每个活i都有一个要求使用该资源的起始时间si和一个结束时间fi,且si < fi 。如果选择了活动i,则它在半开时间区间[si, fi)内占用资源。若区间[si, fi)与区间[sj, fj)不相交,则称活动i与活动j是相容的。也就是说,当si >= fj或sj >= fi时,活动i与活动j相容.怎么尽可能地安排多的相容活动呢?
设待安排的11个活动的开始时间和结束时间按结束时间的非减序排列如下:
注意要按结束时间的早晚排列,没排好的话,你可以回去用各种方法自己排.既然贪心么就是越早结束越好,给后面留尽可能多的空间.其次”目光短浅”,从排列好的里一个个选,能选一个是一个,别管后面的…
显然,我们选择到了(1)1-4,(4)5-7,(8)8-11,(11)12-14
感觉不靠谱么,其实对于这个活动安排问题,贪心算法总能求得的整体最优解,即它最终所确定的相容活动集合A的规模最大。这个结论可以用数学归纳法证明。
代码:
public class MArrange1 {
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
int [] start=initArrange(scanner);
int [] end=initArrange(scanner);
int n=start.length;
// shows(start);
// shows(end);
selectSort(start,end,n);
greedyArrange(start,end,n);
}
private static void greedyArrange(int[] start, int[] end, int n) {
List<Integer> end1=new ArrayList<>();
List<Integer> start1=new ArrayList<>();
end1.add(end[0]);
start1.add(start[0]);
int startTime=end[0];//选择的所有活动的最末结束时间
for (int i = 1; i <n ; i++) {
if(start[i]>startTime)
{
end1.add(end[i]);
start1.add(start[i]);
startTime=end[i];
}
}
System.out.println("result:");//输出结果
for(int i:start1)
System.out.print(i+" ");
System.out.println();
for(int i:end1)
System.out.print(i+" ");
}
private static void selectSort(int[] start, int[] end, int n) {
int [] b=new int[n];
for (int i = 0; i <n ; i++) {
b[i]=i;
}
for (int i = 0; i <n-1 ; i++) {
for (int j = i+1; j <n ; j++) {
if(end[j]<end[i])
{
int temp=end[j];
end[j]=end[i];
end[i]=temp;
int temp1=b[j];
b[j]=b[i];
b[i]=temp1;
}
}
}
// shows(end);
// shows(b);
int c[]=new int[n];
for (int i = 0; i <n ; i++) {
c[i]=start[b[i]];
}
start=c;
// shows(start);
}
private static void shows(int[] start) {
for(int i:start)
System.out.print(i+" ");
System.out.println();
}
private static int[] initArrange(Scanner scanner) {
String string=scanner.nextLine();
String [] strings=string.split(",");
int [] temp=new int[strings.length];
for (int i = 0; i <strings.length ; i++) {
temp[i]=Integer.parseInt(strings[i]);
}
return temp;
}
}