- 贪心算法
依据某种贪心标准,从问题的初始状态出发,直接去求每一步的最优解,通过若干次的贪心选择,最终得出整个问题的最优解。
贪心算法不是从整体上考虑问题,它所做出的选择只是在某种意义上的局部最优解。
如果一个问题可以同时用几种方法解决,贪心算法应该是最好的选择之一。
所需条件:
- 可行的:必须满足问题的约束。
- 局部最优:它是当前步骤中所有可行选择中最佳的局部选择。
- 不可更改:一旦作出选择,在算法的后面步骤就不可改变。
注意:
贪心算法不是对所有问题都能得到整体最优解,选择的贪心策略必须具备无后效性,即某个状态以后的过程不会影响以前的状态,只是当前状态有关。
求解过程:
(1)候选集合A:为了构造问题的解决方案,有一个候选集合A作为问题的可能解,即问题的最终解均取自于候选集合A。
(2)解集合S:随着贪心选择的进行,解集合S不断扩展,直到构成满足问题的完整解。
(3)解决函数solution:检查解集合S是否构成问题的完整解。
(4)选择函数select:即贪心策略,这是贪心法的关键,它指出哪个候选对象最有希望构成问题的解,选择函数通常和目标函数有关。
(5)可行函数feasible:检查解集合中加入一个候选对象是否可行,即解集合扩展后是否满足约束条件。
//A是问题的输入集合即候选集合
Greedy(A)
{
S={ }; //初始解集合为空集
while (not solution(S)) //集合S没有构成问题的一个解
{
x = select(A); //在候选集合A中做贪心选择
if feasible(S, x) //判断集合S中加入x后的解是否可行
S = S+{x};
A = A-{x};
}
return S;
}
经典例题:背包问题
给定一个载重量为M的背包,考虑n个物品,其中第i个物品的重量 ,价值wi (1≤i≤n),要求把物品装满背包,且使背包内的物品价值最大。
#有两类背包问题(根据物品是否可以分割),如果物品不可以分割,称为0—1背包问题(动态规划);如果物品可以分割,则称为背包问题(贪心算法)。
有3种方法来选取物品:
(1)当作0—1背包问题,用动态规划算法,获得最优值220;
(2)当作0—1背包问题,用贪心算法,按性价比从高到底顺序选取物品,获得最优值160。由于物品不可分割,剩下的空间白白浪费。
(3)当作背包问题,用贪心算法,按性价比从高到底的顺序选取物品,获得最优值240。由于物品可以分割,剩下的空间装入物品3的一部分,而获得了更好的性能。
struct bag{ int w; //物品的重量 int v; //物品的价值 double c; //性价比 }a[1001]; //存放物品的数组 排序因子(按性价比降序): bool cmp(bag a, bag b){ return a.c >= b.c; } 使用标准模板库函数排序(最好使用stable_sort()函数,在性价比相同时保持输入的顺序): sort(a, a+n, cmp); //形参n是物品的数量,c是背包的容量M,数组a是按物品的性价比降序排序 double knapsack(int n, bag a[], double c) { double cleft = c; //背包的剩余容量 int i = 0; double b = 0; //获得的价值 //当背包还能完全装入物品i while(i<n && a[i].w<cleft) { cleft -= a[i].w; b += a[i].v; i++; } //装满背包的剩余空间 if (i<n) b += 1.0*a[i].v*cleft/a[i].w; return b; }
- 个人总结:
最近感觉STL对我来说学起来真的是比较吃力,做题时发现不知道怎么运用所学的知识,还有就是即使知道了解题的思路,也没办法完整的写出程序,再就是费了九牛二虎之力写出程序,提交时出来的结果却是W或者超时...再就是可能因为刚开学的原因,时间调整的不是很好,总感觉没有足够的时间来做练习....
从原来那个狭小的空间走出来之后,才发现外面的天空有多么的广阔。天外有天,人外有人,像我这样原来一点没接触过程序的人,感到了深深的压力,这也意味着我要付出更多的努力,加油吧!