解法2:动态规划
AC代码:
//动态规划
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
#pragma warning(push)
#pragma warning(disable:6385)
//801:加20*20修正D-P的值-》直接用下标来表示当前的D-P
int dp[21][801];//dp: 在考虑前i个人的情况下,D-P=k时,D+P最大的情况;
int path[21][801];//dp[i - 1][k0]添加编号为j的人-》dp[i][k], 即path[i][k] = j.
bool isUsed(int* cha, int i, int k, int j) {//j是否出现过
while (i > 0 && path[i][k] != j) {
k -= cha[path[i][k]];
i--;
}
return i ? true : false;
}
int main() {
int n, m, cnt = 1;
while (cin >> n >> m) {
if (n == 0 && m == 0) break;
int t1, t2;
int* cha = new int[n + 1];
int* he = new int[n + 1];
for (int i = 1; i <= n; i++) {
cin >> t1 >> t2;//P, D
cha[i] = t1 - t2;//记录每组数据的差
he[i] = t1 + t2;//和
}
//初始化
int offset = m * 20;//偏置
memset(dp, -1, sizeof(dp));//如果根本不可能让D-P=k,则dp[i][k]=-1.
memset(path, 0, sizeof(path));
dp[0][offset] = 0;
for (int i = 1; i <= m; i++) {//循环1,要选m人
for (int k = 0; k <= 2 * offset; k++) {//循环2,dp[i][k]是否可行
if (dp[i - 1][k] >= 0) {
for (int j = 1; j <= n; j++) {//循环3,从n个人中选择
//判断j号加入当前方案,是否比以前确定的方案更优,
//检查j是否已经在候选人中
if (dp[i][k + cha[j]] < dp[i - 1][k]+he[j] && !isUsed(cha,i-1,k,j)) {
dp[i][k + cha[j]] = dp[i - 1][k] + he[j];
path[i][k + cha[j]] = j;//记录j
}
}
}
}
}
//从dp[m][offset]处往两边找,第一个>=0的就是|D-P|最小的方案,
//如果有两个,要存储的值:即D-P大的.
for (t1 = 0; t1 <= offset; t1++) {
if (dp[m][offset - t1] >= 0 || dp[m][offset + t1] >= 0) break;
}
t1 = dp[m][offset - t1] > dp[m][offset + t1] ? offset - t1 : offset + t1;
//dp[m][t1]: D+P; t1:P-D;
cout << "Jury #" << cnt++ << endl << "Best jury has value " << (dp[m][t1] + t1 - offset) / 2
<< " for prosecution and value " << (dp[m][t1] - t1 + offset) / 2
<< " for defence:" << endl;
int* id = new int[m];
//根据path,找出编号序列
for (int i = 0, j = m, k = t1; i < m; i++) {
id[i] = path[j][k];
k -= cha[id[i]];
j--;
}
//排序
sort(id, id + m);
for (int i = 0; i < m; i++)
cout << " " << id[i];
cout << endl;
delete[] cha;
delete[] he;
delete[] id;
}
return 0;
}
#pragma warning(pop)