贪心算法是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解。
贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择,选择的贪心策略必须具备无后效性,即某个状态以前的过程不会影响以后的状态,只与当前状态有关。
贪心算法其实是一种优化后的动态规划。
典型例题
1.过桥
有 n 个人希望在晚上通过一座桥。在任何时刻,最多只能有两个人在桥上,而且必须要带着电筒才能过桥。一共只有一个手电筒,所以必须安排某种顺序,使得手电筒可以被带回去让更多的人过桥(手电筒必须由人带回,不可以从对岸扔过去)。每个人都有不同的过桥时间,两个人一起过桥所花的时间等于其中较慢的一个。你的任务是要找出能在最短时间内使所有人都过桥的方案。
分析:
由于模拟此题过于复杂,考虑将过河分为几个小的单元来寻找规律。
为了得到最优解,单纯运送手电筒的工作一定会交由过桥时间最短的两人来完成。于是出现了两种情况:
- 最快的人将手电筒运回来,最快的和最慢的过去,最快的再回来,最快的和次慢的过去。
- 最快的人将手电筒运回来,最慢的和次慢的过去,次快的把手电筒运回来,最快的和次快的过去。
经由推理得到公式:t[i]+t[i-1]= min(a[1]*2 + a[i-1] + a[n],a[1] + a[2]*2 + a[i])
由于a[1]+a[i-1] 与 a[2] 的大小关系是不确定的,所以只有通过对实际情况比较来判断。
while(n > 3) { s += min(a[1]*2 + a[n-1] + a[n],a[1] + a[2]*2 + a[n]); n -= 2; } if(n == 1) s += a[1]; else if(n == 2) s += a[2]; else s += a[1]+a[2]+a[3]; printf("%d",s);
2.某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭。输入导弹依次飞来的高度(雷达给出的高度数据是le 50000≤50000的正整数),计算如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。
分析:
所有系统拦截的导弹呈单调递减序列 ->由此说明,若当前没有可以拦截该导弹的系统,则必须增加一个系统。若有,则是当前拦截高度大于等于导弹高度的系统拦截该导弹为最优解。由反证法即可证明。
while(cin>>x) { if(top==0) { q[++top]=x; ans++; } else if(q[top]<x) { ans++; q[++top]=x; } else { for(int i=1;i<=top;i++) if(q[i]>=x) { q[i]=x; break; } } }