贪心法-背包问题

来源:互联网 发布:jquery 1.12.4.min.js 编辑:程序博客网 时间:2024/04/27 13:01

贪心方法的一般策略
–问题的一般特征:问题的解是由n个输入的、满足某些事先给定的条件的子集组成。
–一般方法
根据题意,选取一种度量标准。然后按照这种度量标准对n个输入排序,并按序一次输入一个量。
如果这个输入和当前已构成在这种量度意义下的部分最优解加在一起不能产生一个可行解,则不把此输入加到这部分解中。否则,将当前输入合并到部分解中从而得到包含当前输入的新的部分解。
这一处理过程一直持续到n个输入都被考虑完毕,则记入最优解集合中的输入子集构成这种量度意义下的问题的最优解。

这种能够得到某种量度意义下的最优解的分级处理方法称为贪心方法

贪心方法的抽象化控制描述
procedure GREEDY(A,n)
//A(1:n)包含n个输入//
solution←Φ //将解向量solution初始化为空//
for i←1 to n do
x←SELECT(A) //按照度量标准,从A中选择一个输入,其值赋予x
并将之从A中删除//
if FEASIBLE(solution, x) then //判定x是否可以包含在解向量中,
即是否能共同构成可行解//
solution←UNION(solution, x) //将x和当前的解向量合并成新的解
向量,并修改目标函数//
endif
repeat
return(solution)
end GREEDY

背包问题的描述
–已知n种物品具有重量(w1, w2,…, wn)和效益值(p1, p2,…, pn) ,及一个可容纳M重量的背包;设当物品i全部或一部分xi放入背包将得到pi xi的效益,这里,0≤ xi ≤1, pi >0。
–问题:采用怎样的装包方法才能使装入背包的物品的总效益最大?

分析:
①装入背包的总重量不能超过M
②如果所有物品的总重量不超过M,即≤M,则把所有的物品都装入背包中将获得最大可能的效益值
③如果物品的总重量超过了M,则将有物品不能(全部)装入背包中。由于0≤xi≤1,所以可以把物品的一部分装入背包,所以最终背包中可刚好装入重量为M的若干物品(整个或一部分)

 

问题的形式描述
可 行 解:满足上述约束条件的任一集合(x1,x2,…,xn) 都是问题的一个可行解——可行解可能为多个。 (x1,x2,…,xn)称为问题的一个解向量。
最 优 解:能够使目标函数取最大值的可行解是问题的最优解——最优解也可能为多个

最优的度量标准
在这种策略下的量度是: 已装入的物品的累计效益值与所用容量之比。
故,新的量度标准是: 每次装入要使累计效益值与所用容量的比值有最多的增加(首次装入)和最小的减小(其后的装入)。
此时,将按照物品的单位效益值:pi/wi 比值(密度)的非增次序考虑。

实例分析
(p1,p2,p3) = (25,24,15), (w1,w2,w3) = (18,15,10)
∵ p1/w1<p3/w3 <p2/w2
∴ 首先将物品2放入背包,此时x2=1,背包容量减少w2=15个单位,还剩余空间ΔM=5。同时,背包获得p2=24的效益增量。
其次考虑物品1和3。此时,应选择物品3,且就ΔM=5而言有,也只能放入物品3的一部分到背包中 。即
x3=5/10=1/2

(p1,p2,p3) = (25,24,15), (w1,w2,w3) = (18,15,10)
最后,背包装满ΔM=0,故物品1将不能装入背包,x1=0 。
背包最终可以获得效益值= x1 p1 +x2 p2+x3 p3
= 31.5 (最优解)

背包问题的贪心算法
procedure GREEDY-KNAPSACK(P,W,M,X,n)
//p(1:n)和w(1:n)分别含有按P(i)/W(i)≥P(i+1)/W(i+1)排序的n件物品的效益值和重量。M是背包的容量大小,而x(1:n)是解向量//
real P(1:n), W(1:n), X(1:n), M, cu;
integer i, n
X←0 //将解向量初始化为空//
cu←M //cu是背包的剩余容量//
for i←1 to n do
if W(i) > cu then exit endif
X(i) ←1
cu ←cu-W(i)
repeat
if i≤n then X(i) ←cu/W(i) endif
end GREEDY-KNAPSACK

 

测试过的代码

#include <iostream>using namespace std;void greedy_knapsack(int p[],int w[],float x[],int n,float m){    float cu = m;    int i;    for (i=0;i<n;++i)    {        if(w[i]>cu)            break;        x[i]=1;        cu -= w[i];    }    if(i<=n-1)        x[i] = cu/w[i];}int main(){    //重量    int p[3] = {24,15,25};    //效益值    int w[3] = {15,10,18};    //解向量    float x[3] = {0};    //重量限制是30    int m = 20;    greedy_knapsack(p,w,x,3,m);    for(int i=0;i<3;++i)        cout <<x[i]<<'\t'<< endl;    return 0;}