动态规划—0-1背包

动态规划有以下三个特点:
1:多阶段决策
2:最优值和最优解
3:最优子结构
动态规划采用自底而上的思想保存子问题值,避免重复计算。例如斐波那契数列的递归函数,f(5)=f(3)+f(4),而f(4)=f(3)+f(2),存在重复计算的问题。

0—1背包问题

已知n个物品和一个可以容纳c重量的背包,物品i(1,2,3,4…….,n)的重量为Wi,产生的效益为Pi。在装包时,物品可以装入,也可以不装入,但是不能拆开。即物品i可以产生的效益为XiPi,这里Xi取0或1。
1,最优子结构特性:设(x1,x2,x3,…,xn)是0-1背包的最优解,那么(x2,x3,…,xn)必然是0-1背包子问题的最优解。
2,动态规划逆推求解
按照每一件物品装包为一个阶段,共分为n个阶段。
目标函数:max∑XiPi (i=1,2,…..n)
约束条件:∑XiWi ≤ C (i=1,2,…..n)

设m(i,j)为背包容量为j,可取物品范围为i,i+1,…,n的最大效益。则当0≦j≤W(i)时,物品i 不可能装入,最大效益值与m(i+1,j)相同。
当j≥w(i)时,有以下两种选择:
①不装入物品i,这时最大效益值为m(i+1,j);
②装入物品i时,这时已经产生的效益p(i),背包剩余容量j-w(i),最大效益值为m(i+1,j-w(i))+p(i)。
边界条件为:m(n,j)=p(n) j≥w(n)
m(n,j)=0 j≤w(n)
所求的最优值为m(1,c)。

main(){
/*
c:背包容量
cw:当前装载的所有物品总重量
cp:当前装载的所有物品的总效益
int i,j,c,cw,n,sw,sp,p[5]0,w[50],m[50][500];
printf("input n:");
scanf("%d",&n);
printf("input c:",&c);
for(i=1;i<=n;i++)
{
printf("input w%d,p%d:",i,i);
scanf("%d,%d",&w[i],&p[i]);
}
for(j=0;j<=c;j++)  //首先计算m(n,j),但是不确定装最后一个物品时j的值
//所以这里将所有j可能出现的情况都赋值了
if(j>=w[n])
m[n][j]=p[n];
else
m[n][j]=0;
for(i=n-1;i>=1;i--)   //逆推计算m(i,j)
for(j=0;j<=c;j++)
if(j>w[i]&&m[i+1][j]<m[i+1][j-w[i]]+p[i])
m[i][j]=m[i+1][j-w[i]]+p[i];
else
m[i][j]=m[i+1][j];

cw=c;
printf("c=%d\n",c);
printf("背包所装物品:\n");
printf(" i   w(i)   p(i)\n");
for(sp=0,sw=0,i=1;i<=n;i++)   //以表格的形式输出
if(m[i][cw]>m[i+1][cw])
{
cw-=w[i];sw+=w[i];sp+=p[i];
printf("%2d   %3d   %3d\n",i,w[i],p[i]);
}
if(m[1][c]-sp=p[n]){
sw+=w[n];sp+=p[n];
printf("%2d   %3d   %3d\n",i,w[i],p[i]);
}
printf("w=%d,   pmax=%d\n",sw,sp);

}

上面我们用m[i][j]来保存子问题的值,而且采用自底而上的方法,首先计算m[n][j],每进行下一个阶段决策,直接调用上一阶段的值,这样就不会存在重复计算了。

采用順推的方式实现:
m(i,j)表示为背包容量为j,可取物品范围为1,2,3,….,i的最大效益。
0≦j≤W(i)时,物品i 不可能装入,最大效益值与m(i-1,j)相同。
当j≥w(i)时,有以下两种选择:
①不装入物品i,这时最大效益值为m(i-1,j);
②装入物品i时,这时已经产生的效益p(i),背包剩余容量j-w(i),最大效益值为m(i+1,j-w(i))+p(i)。
边界条件为:m(1,j)=p(1) j≥w(1)
m(1,j)=0 j≤w(1)
所求的最优值为m(n,c)。
下面只贴一下部分不同的代码:

for(j=0;j<=c;j++)  //首先计算m(1,j),但是不确定装第一个物品时j的值
//所以这里将所有j可能出现的情况都赋值了
if(j>=w[1])
m[1][j]=p[1];
else
m[1][j]=0;
for(i=2;i<=n;i++)   //順推计算m(i,j)
for(j=0;j<=c;j++)
if(j>w[i]&&m[i+1][j]<m[i+1][j-w[i]]+p[i])
m[i][j]=m[i-1][j-w[i]]+p[i];
else
m[i][j]=m[i-1][j];

拓展:带约束条件的0-1背包问题,例如多了一个背包最大容量为d的约束条件,
其实只需要在加一个约束条件就行了

for(i=2;i<=n;i++)   //順推计算m(i,j)
for(j=0;j<=c;j++)
for(k=0;k<=d;k++)
if(j>w[i]&&k>=v[i]&&m[i+1][j][k]<m[i+1][j-w[i]][k-v[i]]+p[i])
m[i][j][k]=m[i-1][j-w[i]][k-v[i]]+p[i];
else
m[i][j][k]=m[i-1][k-v[i]][j];
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值