1.对贪心算法的认识
贪心算法在求解问题时,不从整体上考虑,而是得到某种意义上的局部最优解,做出当前看来是最好的选择。每次的选择都会依赖之前作出的选择,而对后面的选择不会产生影响。
它具有最优子结构的性质,即问题的最优解包含其子问题的最优解。但贪心算法不是对于所有的问题都能得到整体最优解,最重要的是贪心策略的选择。
与动态规划相比,贪心算法的特点在于它是自顶向下进行分解,每一步的最优解包含上一步的最优解,但上一步之前的最优解不保留最终得到某种意义上是的局部最优解,动态规划则会记录所有的局部最优解。
2.贪心性质的证明
选择的问题:区间选点
问题描述:
数轴上有n个闭区间[ai, bi]。取尽量少的点,使得每个区间内都至少有一个点(不同区间内含的点可以是同一个)。
输入格式:
第一行一个数字n,表示有n个闭区间。 下面n行,每行包含2个数字,表示闭区间[ai, bi]
输出格式:
一个整数,表示至少需要几个点
输入样例:
在这里给出一组输入。例如:
3
1 3
2 4
5 6
输出样例:
2
代码:
#include<iostream> #include<algorithm> #define MAX 1000 using namespace std; struct Area{ int start; int end; }areas[MAX]; bool cmp(struct Area a, struct Area b){ if(a.end < b.end) return true; else return false; } int main(){ int n; cin >> n; for(int i = 0; i < n; i++){ cin >> areas[i].start >> areas[i].end; } sort(areas,areas + n,cmp); int count = 0; int finish = 0; for(int i = 0; i < n; i++){ if(areas[i].start > finish){ finish = areas[i].end; count++; } } cout << count << endl; }
贪心策略:将每个区间按照结尾由早至晚进行排序,每次选择结尾最早且与前一个区间不会重叠的区间。
证明:
当其中一次选择的是区间[S(i),T(i)]时,T(i)则为当前选择中结尾最早的选择。
若此问题的最优解为K,假设选择[S(i),T(i)]不是最优的,而选择了[S(j),T(j)],(j > i),此时得到的解为K-1。若用[S(i),T(i)]代替[S(j),T(j)],不会影响后面的选择。此时得到的解仍为K-1,而在假设中,选择了[S(i),T(i)]的方法不是最优的,所以产生了矛盾。
以上证明,选择的贪心策略是正确的。
3.本章问题及结对编程的总结
贪心算法相比动态规划来说,会容易理解一些。最重要的,就是求解问题时如何选择正确的贪心策略。
结对编程:通过前几次结对编程,和队友之间的合作更加顺畅默契,在交流中也能更积极地给对方提供更多的思路,再通过讨论确定正确的方案。