在一个遥远的国家,一名嫌疑犯是否有罪需要由陪审团来决定。
陪审团是由法官从公民中挑选的。
法官先随机挑选 N N N 个人(编号 1 , 2 … , N 1,2…,N 1,2…,N)作为陪审团的候选人,然后再从这 N N N 个人中按照下列方法选出 M M M 人组成陪审团。
首先,参与诉讼的控方和辩方会给所有候选人打分,分值在
0
0
0 到
20
20
20 之间。
第
i
i
i 个人的得分分别记为
p
[
i
]
p[i]
p[i] 和
d
[
i
]
d[i]
d[i]。 为了公平起见,法官选出的
M
M
M 个人必须满足:辩方总分
D
D
D 和控方总分
P
P
P 的差的绝对值
∣
D
−
P
∣
|D−P|
∣D−P∣ 最小。
如果选择方法不唯一,那么再从中选择辨控双方总分之和
D
+
P
D+P
D+P 最大的方案。求最终的陪审团获得的辩方总分
D
D
D、控方总分
P
P
P,以及陪审团人选的编号。
注意:若陪审团的人选方案不唯一,则任意输出一组合法方案即可。
输入格式:
输入包含多组测试数据。
每组测试数据第一行包含两个整数
N
N
N 和
M
M
M。
接下来
N
N
N 行,每行包含两个整数
p
[
i
]
p[i]
p[i] 和
d
[
i
]
d[i]
d[i]。
每组测试数据之间隔一个空行。
当输入数据
N
=
0
,
M
=
0
N=0,M=0
N=0,M=0 时,表示结束输入,该数据无需处理。
输出格式:
对于每组数据,第一行输出 KaTeX parse error: Expected 'EOF', got '#' at position 6: Jury #̲C,
C
C
C
为数据编号,从
1
1
1 开始。
第二行输出
B
e
s
t
j
u
r
y
h
a
s
v
a
l
u
e
P
f
o
r
p
r
o
s
e
c
u
t
i
o
n
a
n
d
v
a
l
u
e
D
f
o
r
d
e
f
e
n
c
e
:
Best jury has value P for prosecution and value D for defence:
BestjuryhasvaluePforprosecutionandvalueDfordefence:,
P
P
P为控方总分,
D
D
D 为辩方总分。
第三行输出按升序排列的陪审人选编号,每个编号前输出一个空格。
每组数据输出完后,输出一个空行。
数据范围:
1
≤
N
≤
200
1≤N≤200
1≤N≤200
1
≤
M
≤
20
1≤M≤20
1≤M≤20
0
≤
p
[
i
]
,
d
[
i
]
≤
20
0≤p[i],d[i]≤20
0≤p[i],d[i]≤20
输入样例:
4 2
1 2
2 3
4 1
6 2
0 0
输出样例:
Jury #1
Best jury has value 6 for prosecution and value 4 for defence:
2 3
首先 遇到背包问题, 确定背包类型, 每个人只能选一个, 故为 01 01 01 背包, 然后题目要求具体方案, 首先答案要求满足两个条件, 第一是要 ∣ D − P ∣ |D - P| ∣D−P∣ 最小,其次是 D + P D + P D+P 最大, 我们可以将 D + P D + P D+P 定义为背包的属性
状态定义:
f
[
i
]
[
j
]
[
k
]
f[i][j][k]
f[i][j][k]: 在前
i
i
i 个人中选, 总人数不超过
j
j
j, 并且总差值为
k
k
k 的集合
状态属性:
D
+
P
D + P
D+P 的最大值
状态计算: 选第
i
i
i 个人 不选第
i
i
i 个人
f
[
i
]
[
j
]
[
k
]
=
m
a
x
(
f
[
i
−
1
]
[
j
]
[
k
]
,
f
[
i
−
1
]
[
j
−
1
]
[
k
−
(
p
[
i
]
−
d
[
i
]
)
]
+
p
[
i
]
+
d
[
i
]
)
;
f[i][j][k] = max(f[i - 1][j][k], f[i - 1][j - 1][k - (p[i] - d[i])] + p[i] + d[i]);
f[i][j][k]=max(f[i−1][j][k],f[i−1][j−1][k−(p[i]−d[i])]+p[i]+d[i]);
求出 D + P D + P D+P 的最大值并不难, 难点在于如何得到具体方案,我们可以通过方向搜一遍, 如果从终点状态,一直迭代到起始状态,能够进行状态转移,我们就记下这个方案
注意: 由于p[i] 是从 1 1 1 ~ 20 20 20, 所以 p [ i ] − d [ i ] p[i] - d[i] p[i]−d[i] 是从 − 40 -40 −40 ~ 40 40 40, 所以总的 p [ i ] − d [ i ] p[i] - d[i] p[i]−d[i] 是从 − 400 -400 −400 ~ 400 400 400, 但是如果直接使用,会导致数组越界,所以我们加上一个偏移量取名为 b a s e base base,其值 400 400 400, 故差值的范围就会变成 0 0 0 ~ 800 800 800
#include<bits/stdc++.h>
using namespace std;
const int N = 210, M = 810, base = 400;
int f[N][21][M], p[N], d[N], ans[N], n, m;
int main()
{
int T = 1;
while(cin >> n >> m, n, m)
{
for(int i = 1; i <= n; i ++ ) cin >> p[i] >> d[i]; //读入
memset(f, -0x3f, sizeof f); //因为求最大值, 故赋值为负无穷
f[0][0][base] = 0; //初始化为0
int cnt = 0; //初始化
for(int i = 1; i <= n; i ++) //枚举前i个人
for(int j = 0; j <= m; j ++) //枚举已经选了的人
for(int k = 0; k < M; k ++ ) //枚举差值 0~801
{
f[i][j][k] = f[i - 1][j][k]; //不选第 i 个人
int t = k - (p[i] - d[i]); //计算出差值,看是否符合题意
if(t < 0 || t > M ) continue;
if(j < 1) continue; //是否可以转移
f[i][j][k] = max(f[i][j][k], f[i - 1][j - 1][t] + p[i] + d[i]); //状态转移
}
int v = 0;
while( f[n][m][base + v] < 0 && f[n][m][base - v] < 0) v ++;
// 当v小于0和v大于0 都不合题意是, v++;
if(f[n][m][base + v] > f[n][m][base - v]) v = base + v;
else v = base - v;
//当v,-v都存在时,取最大值
int j = m, i = n, k = v;
while(j)
{
if(f[i][j][k] == f[i - 1][j][k]) i --;//如果可以不选第i个人
else
{
ans[cnt ++ ] = i; //选了第i个人
k -= p[i] - d[i]; //差值减小
i --, j --; //减小
}
}
int a = 0, b = 0;
for(int i = 0; i < cnt; i ++ ) a += p[ans[i]], b += d[ans[i]];
//记录答案
printf("Jury #%d\n", T++);
printf("Best jury has value %d for prosecution and value %d for defence:\n", a, b);
sort(ans, ans + cnt); //排序,保证编号是从小到大的
//打印方案
for(int i = 0; i < cnt; i ++ ) cout << ans[i] << ' ';
cout << '\n';
cout << '\n';
}
}