AcWing 280. 【Java】陪审团
原题链接
中等
作者:
tt2767
,
2020-01-14 00:55:32
,
所有人可见
,
阅读 877
/*
1. 状态定义:"辩方总分D、控方总分P" -> 定义d[i]-p[i]为 物品代价, 不用abs(d[i]-p[i])的原因是abs无法递推!
"如果选择方法不唯一,那么再从中选择辨控双方总分之和D+P最大的方案" -> 定义 d[i]+p[i] 为物品价值
代价->价值的转换 ->背包问题
“求最终的陪审团获得的辩方总分D、控方总分P,以及陪审团人选的编号。” -> 背包路径
即f[i][j][k] 为 已经处理了1...i个人,并且选择了j个人,代价为k, 的最大价值
2. 状态计算: 不选i或 选i划分 为2个集合并取最大值
不选i f[i][j][k] = f[i-1][j][k]
选i f[i][j][k] = f[i-1][j-1][k-abs(d[i]-p[i])] + (d[i]+p[i])
3. 边界: f[~][~][~] = -INF, f[0][0][0] = 0
*/
import java.util.*;
public class Main{
void run(){
int c = 1;
while(jin.hasNext()){
int n = jin.nextInt();
int m = jin.nextInt();
if (n == 0 && m == 0) break;
for(int i = 1 ; i <= n ; i++){
p[i] = jin.nextInt();
d[i] = jin.nextInt();
}
dp(n, m);
System.out.printf("Jury #%d\n", c++);
System.out.printf("Best jury has value %d for prosecution and value %d for defence:\n", resp, resd);
list.forEach(x->System.out.printf(" %d", x));
System.out.println();
System.out.println();
}
}
void dp(int n, int m ){
for (int i = 0 ; i <= n ; i++){
for (int j = 0 ; j <= m ; j++){
for (int k =0 ; k < maxK; k++ ){
f[i][j][k] = Integer.MIN_VALUE ;
}
}
}
f[0][0][BASE] = 0; // 初值为0
list.clear();
resp = 0;
resd = 0;
for (int i = 1 ; i <= n ; i++){
for (int j = 0 ; j <= m ; j++){ // j= 0
for (int k =0 ; k < maxK; k++ ){
f[i][j][k] = f[i-1][j][k];
int diff = k - ( p[i] - d[i]);
if ( diff < 0|| diff >= maxK ) continue;
if (j < 1) continue;
f[i][j][k] = Math.max(f[i-1][j][k], f[i-1][j-1][diff] + (d[i] + p[i]));
}
}
}
int cost = 0;
while(f[n][m][BASE + cost] < 0 && f[n][m][BASE - cost] < 0) cost ++; // 必须是绝对值存在
if(f[n][m][BASE + cost] > f[n][m][BASE - cost]) cost = BASE + cost; // 取绝对值最大的
else cost = BASE - cost; // 不能是-= BASE ,不然可能变负值了
for (int j = m, i = n, k = cost ; j >= 1 && i >= 1 ; i--){
if (f[i][j][k] == f[i-1][j][k]) continue; // 判断不是要比判断是方便的多
list.add(i); // 反着数的
resp += p[i];
resd += d[i];
j--;
k -= (p[i]-d[i]);
}
// Collections.reverse(list); // 方案不唯一,不用翻转也行
}
int maxM = 22;
int maxN = 202;
int BASE = 400;
int maxK = 808;
int resp = 0;
int resd = 0;
List<Integer> list = new ArrayList<Integer>();
int[][][] f = new int[maxN][maxM][maxK];
int[] d = new int[maxN];
int[] p = new int[maxN];
Scanner jin = new Scanner(System.in);
public static void main(String[] args) {new Main().run();}
}