Java-POJ1014-Dividing

多重背包问题的特点是物品数量可以大于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 }
~~Jason_liu O(∩_∩)O
原文地址:https://www.cnblogs.com/JasonCow/p/12248400.html