整理一下0-1背包、完全背包、多重背包问题。
背包问题
01背包
概述
01背包是在M件物品取出若干件放在空间为W的背包里,每件物品的体积为W1,W2至Wn,与之相对应的价值为P1,P2至Pn。(这是最基础的背包问题)
思路
在前n件物品中,选取若干件物品放入所剩空间为w的背包中的所能获得的最大价值。(实际上是对一件件物品选与不选的问题)
我们用f[i][j]表示在前 i 件物品中选择若干件放在已用空间为 j 的背包里所能获得的最大价值
对一个物体,只有两种情况:
- 选:f[i][j] = f[i - 1][j - W[i]] + P[i]
- 不选:f[i][j] = f[i - 1][j]
由此可以得到状态转移方程:
f[i][j] = max(f[i - 1][j - W[i]] + P[i], f[i - 1][j]);
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
public static int[][] backpack01(int m,int n,int[] w,int[] p){ int[][] f = new int[n + 1][m + 1]; for(int i = 0; i < n + 1; i++){ f[i][0] = 0; } for(int j = 0; j < m + 1; j++){ f[0][j] = 0; }
for(int i = 1; i < n + 1; i++){ for(int j = 1; j < m + 1; j++){ if(w[i - 1] <= j){ if(f[i - 1][j] < f[i - 1][j - w[i - 1]] + p[i - 1]){ f[i][j] = f[i - 1][j - w[i - 1]] + p[i - 1]; }else{ f[i][j] = f[i - 1][j]; } }else{ f[i][j] = f[i - 1][j]; } } } return f; }
|
完全背包
概述
完全背包问题跟01背包的区别是01背包每个物品只能选一次,总共就这几个,而完全背包问题是每个物品可以无限选,只要装得下。可以看成是有几种物品,每种都无限多个。
思路
01背包在选第i个物品时,容积够用情况下,只有2种状态可选,放还是不放,找出最大价值的选择
而完全背包在选第i种物品时,容积够用情况下,可能有2种以上状态可选,放1个,或者2个,3个,或者不放。找出最大价值的选择
可以利用k = j/w[i]算出最多可以放几个,然后状态转移方程改为f[i][j] = max(f[i - 1][j - k*w[m]] + k * p[i])
从0到k遍历一遍求出最大值即可
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
|
public static int[][] backpack02(int m,int n,int[] w,int[] p){
int[][] f = new int[n + 1][m + 1]; for(int i = 0; i < n + 1; i++){ f[i][0] = 0; } for(int j = 0; j < m + 1; j++){ f[0][j] = 0; }
for(int i = 1; i < n + 1; i++){ for(int j = 1; j < m + 1; j++){ if(w[i - 1] <= j){ int k = j / w[i - 1]; for(int t = 0; t < k + 1; t++){ if(f[i - 1][j - t * w[i - 1]] + t * p[i - 1] > f[i][j]){ f[i][j] = f[i - 1][j - t * w[i - 1]] + t * p[i - 1]; } } }else{ f[i][j] = f[i - 1][j]; } } } return f; }
|
多重背包
概述
与“完全背包”相比,在每个物品的选取次数上给出了限定,即选取次数k不能无限的增大
思路
其实与完全背包相似,只是k的限定条件发生了变化。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
|
public static int[][] backpack03(int m,int n,int[] w,int[] p,int[] num){
int[][] f = new int[n + 1][m + 1]; for(int i = 0; i < n + 1; i++){ f[i][0] = 0; } for(int j = 0; j < m + 1; j++){ f[0][j] = 0; }
for(int i = 1; i < n + 1; i++) { for (int j = 1; j < m + 1; j++) { for (int k = 0; (k <= num[i - 1]) && (k >= 0); k++) { if (j > k * w[i - 1]) { if (f[i - 1][j - k * w[i - 1]] + k * p[i - 1] > f[i][j]) { f[i][j] = f[i - 1][j - k * w[i - 1]] + k * p[i - 1]; } } } } } return f; }
|
Last updated: