————2020.1.17————
Posted zzl1209
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了————2020.1.17————相关的知识,希望对你有一定的参考价值。
# 算法 || 背包问题总结 #
1、0 1背包。
何谓0-1背包,可以这样想,那里有一堆值钱的东西,每一样东西只有一件,他们的价值和体积都不一样,现在要你从这n件里面挑选一些放到一个容量一定的背包里面,使得你的背包里的东西总价值最大。对于这些东西的每一件,你可以选择放进你的背包或者是不放进去。(这里放与不放就对应着两种状态0,1),所以称之为0-1背包。
规定f[i][v]来表示前i件物品放入到容量为v的背包里所获得的最大总价值,c[i]为第i件物品的体积,w[i]表示第i件物品的价值
转移方程:f[i][v] = max(f[i-1][v],f[i-1][v-c[i]]+w[i])
据观察当前状态只与二维数组前一行有关,定义f[v]为前i件物品放进容量为v的背包里所获得的最大价值。
转移方程: f[v]=max{f[v] , f[v-c[i]]+w[i]}
伪码如下:
for i=1..n
for j=v..0
f[j]=max{f[j],f[j-c[i]]+w[i]};
2、完全背包。
和0-1背包一样,只是现在每一样物品都有无限件可以选。
转移方程:f[i+1][j] = max{f[i][j-k*c[i]]+k*w[i]} 0<=k<=j/c[i]
写一个三重循环出来,效率显然很低。
在f[i+1][j]的计算中选择k个的情况与在f[i+1][j-c[i]]的计算中选择k-1个的情况是一样的,所以f[i+1][j]的递推中k>=1的部分的计算已经在f[i+1][j-c[i]]的计算中完成了。那么可以根据如下方式进行变换。
f[i+1][j] = max{f[i][j-k*c[i]]+k*v[i] k>=0}
= max{f[i][j] , max{f[i][j-k*c[i]]+k*v[i]} k>=1}
= max{f[i][j] , max{f[i][(j-c[i])-k*c[i]]+v[i]+k*v[i]} k>=0} (注意联系k的取值范围)
= max {f[i][j], f[i+1][j-c[i]]+v[i]}
代码
1 public void helper() 2 { 3 for(int i=0;i<n;i++) 4 for(int j=0;j<=W;j++) 5 { 6 if(j<w[i]) 7 dp[i+1][j] = dp[i][j]; 8 else 9 dp[i+1][j] = Math.max(dp[i][j],dp[i+1][j-c[i]+v[i]); 10 } 11 }
一维优化为
f[i][v]=max{f[i-1][v-k*c[i]]+k*w[i]|0<=k*c[i]<=v}
伪码如下:
for i=1..n
for j=c[i]..v
f[v]=max{f[j],f[j-c[i]]+w[i]}
3、多重背包
对于第i件物品,个数为m[i]。
转移方程只需稍作修改
f[i][v]=max{f[i-1][v-k*c[i]]+k*w[i]|0<=k<=m[i]}
优化的方法:
运用二进制进行物品拆分,转化成01背包。
如:把13个相同的物品分成4组(1,2,4,6)
用这4组可以组成任意一个1~13之间的数
原理:一个数总可以用2^k表示
而且总和等于13,所以不会组成超过13的数
所以可将一种有C个的物品拆分成1,2,4,...,2^(k-1),C-(2^k-1)
然后进行01背包
#Edit : 2020.1.17
以上是关于————2020.1.17————的主要内容,如果未能解决你的问题,请参考以下文章