动态规划—0-1背包

来源:互联网 发布:linux编写shell程序 编辑:程序博客网 时间:2024/06/09 00:25

动态规划有以下三个特点:
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];elsem[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];elsem[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];elsem[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];elsem[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];elsem[i][j][k]=m[i-1][k-v[i]][j];
原创粉丝点击