背包问题算法设计
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
背包问题算法设计
题目描述:
有n个物品,每个物品的重量为w[i],取物品则效益增加p[i],对于给定的一个能容纳重量为M的背包,怎样装包才能使获得的效益最大?每个物品的取值为x[i],x[i]=0/1,0表示该物品不装包,1表示将该物品装入包中。
以上描述就是一个经典的0/1背包问题。
输入输出:
输入一个n,然后输入w[1,2,...,n],p[1,2,...,n]
输出最大效益值和x[1,2,...,n]用0/1表示
sampleinput
3//n
234//w[i]
125//p[i]
sampleoutput
6//最大效益值
101//x[i]
解题思路:
假定决策次序为x[n],x[n-1],...,x[1]。在对x[n]做出决策之后,问题处于下列两种状态之一:
背包的剩余容量为M,没有产生任何效益;
剩余容量是M-w,效益增长了p。
显然,余下来的x[n-1],x[n-2],..,x[1]的决策相对于x所产生的问题状态应该是最优的,否则x[n],x[n-1],...,x[1]就不能是最优决策序列。
设f[j][x]是从物品1-j,背包容量为x的最优解
则最优序列的解f[n][m]
对于任意的f[i][x]=max{f[i-1][x],f[i-1][x-wi]+pi}---------------------------(1)
为了能向后递推而最后求出f[n][m],需要从f[0][x]开始。对于所有x>=0,有f[0][x]=0,
当x<0时,有f[0][x]=负无穷。根据(1)马上可解出0<=x
接着又可以不断递推出f[2],f[3],...,f[n]在x相应的取值范围内的值。
于是有求f[n][m]的算法:
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
if(j-w[i]>=0)
f[i][j]=MAX(f[i-1][j],f[i-1][j-w[i]]+p[i]);
else
f[i][j]=f[i-1][j];
}
一般而言,背包问题是要求一个最优值,如果要求输出这个最优值的方案,可以参照一般动态规划问题输出方案的方法:记录下每个状态的最优值是由状态转移方程的哪一项推出来的,换句话说,记录下它是由哪一个策略推出来的。便可根据这条策略找到上一个状态,从上一个状态接着向前推即可。
设g[i][v]=0表示推出f[i][v]的值时是采用了方程的前一项(也即f[i][v]=f[i-1][v]),g[i][v]表示采用了方程的后一项。注意这两项分别表示了两种策略:未选第i个物品及选了第i个物品。
于是改写求f[n][m]的过程为:
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
if(j-w[i]>=0)
{
f[i][j]=MAX(f[i-1][j],f[i-1][j-w[i]]+p[i]);
if(f[i][j]==f[i-1][j-w[i]]+p[i])
g[i][j]=1;
}
else
f[i][j]=f[i-1][j];
}
}
那么求方案的向量的伪代码可以这样写i=n;
j=m;
while(i>0)
{
if(g[i][j]==0)
x[i]=0;
else
{
x[i]=1;
j=j-w[i];
}
i--;
}
最后输出向量x和f[n][m]既可。
算法空间分析:
时间复杂度O(n*m)
时间复杂度O(n*m)
代码设计:
#include
#defineN200
#defineMAX(a,b)(a>b?a:b) intmain()
{
intn,m,i,j;
intw[N],p[N],x[N];
intf[N][N],g[N][N]; freopen("in.txt","r",stdin); while(cin>>n>>m)
{
for(i=1;i<=n;i++)
cin>>w[i];
for(i=1;i<=n;i++)
cin>>p[i];
memset(f,0,sizeof(f)); memset(g,0,sizeof(g));
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
if(j-w[i]>=0)
{
f[i][j]=MAX(f[i-1][j],f[i-1][j-w[i]]+p[i]); if(f[i][j]==f[i-1][j-w[i]]+p[i])
g[i][j]=1;
}
else
f[i][j]=f[i-1][j];
}
}
i=n;
j=m;
while(i>0)
{
if(g[i][j]==0)
x[i]=0;
else
{
x[i]=1;
j=j-w[i];
}
i--;
}
for(i=1;i<=n;i++) cout< cout< cout< return0; }