多重背包问题的特点是物品数量可以大于1但是有限制。状态定义与01背包一致。
多重背包的解法有多种,复杂度也各不相同。
对于物品数Ci较大的数据,可以采取二进制数进行优化(就是这样,别问就是baidu!)
如何理解多重背包的二进制优化?
使得每种物品的转移次数由O(MxCi)变为O(Mxlog(Ci))
f[i]=f[i] | f[i-a[i]] | …| f[i-a[i]xc[i]](a[i]为物品价值,c[i]为物品数量)
二进制优化后令W[i]=a[i]xc[i](c[i]被二进制分拆)
/* Memory: 3508K Time: 329MS Language: Java Result: Accepted */
实现见代码:
1 package poj.ProblemSet; 2 3 import java.util.Scanner; 4 5 public class poj1014 { 6 public static final int MAXN = 400000; 7 public static boolean[] f = new boolean[MAXN]; 8 public static int[] w = new int[100]; 9 10 public static void main(String[] args) { 11 Scanner cin = new Scanner(System.in); 12 for (int Case = 0; cin.hasNext(); ) { 13 int value = 0, cnt = 0; 14 boolean flag = false; 15 for (int i = 1; i <= 6; i++) { 16 int val = cin.nextInt(); 17 value += val * i; 18 for (int j = 1, x = 0; val > 0; j *= 2) { 19 x = Math.min(j, val); 20 w[++cnt] = i * x; 21 val -= x; 22 } 23 } 24 if (value == 0) break; 25 System.out.println("Collection #" + (++Case) + ":"); 26 if (value % 2 == 0) { 27 f[0] = true; 28 for (int i = 1; i < MAXN; i++) f[i] = false; 29 for (int i = 1; i <= cnt; i++) 30 for (int j = value / 2; j >= w[i]; j--) 31 f[j] |= f[j - w[i]]; 32 flag = true; 33 } 34 System.out.println((!flag?"Can't":(f[value/2]?"Can":"Can't"))+" be divided."); 35 System.out.println(); 36 } 37 } 38 }
PS:另外一种O(VN)的方法是用数据结构单调队列优化!!!Orz
/* Memory: 6064K Time: 282MS Language: Java Result: Accepted */
1 package poj.ProblemSet; 2 3 import java.util.Scanner; 4 5 public class poj1014 { 6 public static final int MAXN = 400000; 7 public static int[] queue = new int[MAXN]; 8 public static boolean[] f = new boolean[MAXN]; 9 public static int[] c = new int[7]; 10 public static void main(String[] args) { 11 Scanner cin = new Scanner(System.in); 12 for (int Case = 0; cin.hasNext(); ) { 13 int value = 0; 14 boolean flag = false; 15 for (int i = 1; i <= 6; i++) { 16 c[i] = cin.nextInt(); 17 value += i * c[i]; 18 } 19 if (value == 0) break; 20 System.out.println("Collection #" + (++Case) + ":"); 21 if (value % 2 == 0) { 22 f[0] = true; 23 for (int i = 1; i <= value / 2; i++) f[i] = false; 24 for (int i = 1, x = 0; i <= 6; i++) { 25 x = i * c[i]; 26 for (int j = 0; j < i; j++) 27 if (f[j]) queue[j] = j; 28 else queue[j] = -MAXN; 29 for (int j = i; j <= value / 2; j++) 30 if (f[j]) queue[j] = j; 31 else { 32 queue[j] = queue[j - i]; 33 if (queue[j - i] + x >= j) f[j] = true; 34 } 35 } 36 flag = true; 37 } 38 System.out.println((!flag?"Can't":(f[value/2]?"Can":"Can't"))+" be divided."); 39 System.out.println(); 40 } 41 } 42 }