1015:Jury Compromise

解法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)  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值