时间限制:10000ms
单点时限:1000ms
内存限制:256MB
描述
小Hi现在有n个物品,每个物品都有一个价值。并且这n个物品总共有m个不同的属性,每个物品都具有其中若干属性。
小Ho要从中选出若干物品,满足每个属性都正好有奇数个物品拥有,且被选出的物品价值总和最大。你能帮助小Ho完成任务么?
输入
第一行一个数T(<=10),表示数据组数。对于每一组数据:
第一行两个数n,m(1<=n<=1000,m<=10)
接下来每两行描述一件物品。对于每一件物品:
第一行两个数v和s,表示其价值和所含属性数量(v<=100000,s<=m)
第二行s个数,表示该物品拥有的属性编号(1<=编号<=m)
输出
物品价值总和的最大值。
- 样例输入
-
1 3 2 2 1 1 2 1 2 5 2 1 2
- 样例输出
-
5
思路
状态压缩DP。
状态定义:
dp[i][j]表示可选物品为[0, i]时,各属性奇偶状态为j的最大价值。
状态转移:
不选择第i个物品时,dp[i][j] = max(dp[i][j], dp[i - 1][j]);
选择第i个物品时,dp[i][s1] = max(dp[i][s1], dp[i - 1][j] + v[i]),其中s1 = j ^ p[i],对应于添加物品i后发生的状态转移。
代码
1 import java.util.Arrays; 2 import java.util.Scanner; 3 4 public class Main { 5 6 public static int resolve(int[] v, int[] p, int n, int m) { 7 final int STATES = 1 << m; 8 int[][] dp = new int[n + 1][STATES]; 9 for (int i = 0; i <= n; i++) { 10 Arrays.fill(dp[i], -1); 11 } 12 13 dp[0][0] = 0; 14 for (int i = 1; i <= n; i++) { 15 for (int j = 0; j < STATES; j++) { 16 if (dp[i - 1][j] < 0) 17 continue; 18 dp[i][j] = Math.max(dp[i][j], dp[i - 1][j]); 19 int s1 = j ^ p[i - 1]; 20 dp[i][s1] = Math.max(dp[i][s1], dp[i - 1][j] + v[i - 1]); 21 } 22 } 23 24 return dp[n][STATES - 1]; 25 } 26 27 public static void main(String[] args) { 28 Scanner sc = new Scanner(System.in); 29 int t = sc.nextInt(); 30 while (t-- > 0) { 31 int n = sc.nextInt(); 32 int[] v = new int[n]; 33 int[] p = new int[n]; 34 int m = sc.nextInt(); 35 for (int i = 0; i < n; i++) { 36 v[i] = sc.nextInt(); 37 int pcnt = sc.nextInt(); 38 for (int j = 0; j < pcnt; j++) { 39 p[i] |= (1 << (sc.nextInt() - 1)); 40 } 41 } 42 43 System.out.println(resolve(v, p, n, m)); 44 } 45 } 46 }