POJ1015 Jury Compromise

题目来源:http://poj.org/problem?id=1015

题目大意:

  有一个国家,法庭的判决由公众中选出的陪审团来进行。每进行一次审讯,就要选出一个陪审团。陪审团人选的选取规则如下:首先,从所有人中随机选取一些人。对于选中的这些人,控方和辩方给每个人打一个分(0到20)来表达他们是否喜欢这个人。0表示完全不喜欢,20表示特别喜欢。基于控方和辩方的两个打分,法官希望选出的陪审团对双方都最公平有利。用di表示辩方给候选人i的打分,pi表示控方给i的打分,现在要从n个候选人中选出m个人成为陪审团。用J表示{1,...,n}的一个m个元素的子集,D(J)表示sum(dk),k属于J,P(J)表示sum(pk),k属于J.选取一个J使得|D(J)-P(J)|最小。如果有多个这样的J,则选取D(J)+P(J)最大的那一个。

输入:由多个用例组成。每个用例的第一行含两个整数n和m。n为候选人数目,m为陪审团人数。1<=n<=200,1<=m<=20.m<=n.接下来的n行每行由一个整数对di和pi组成,i=1,2,...,n.n=m=0代表输入结束。

输出:对于每一个测试用例,找出最合适的陪审团。输出格式见Sample Output.注意每个陪审团成员编号前输出一个空格,每个测试用例后输出一个空白行。


Sample Input

4 2 
1 2 
2 3 
4 1 
6 2 
0 0 

Sample Output

Jury #1 
Best jury has value 6 for prosecution and value 4 for defence: 
 2 3

参考了这篇解题报告:http://blog.csdn.net/lyy289065406/article/details/6671105

  用了动态规划的方法。

  设控辩总分之差为“控辩差”,控辩总分之和为“控辩和”。第i个候选人的控辩差为v(i),控辩和为s(i).

  dp(j,k)表示取j个候选人,使其控辩差为k的所有方案中,控辩和的最大值。假设无法选出这样的j个人则令dp(j,k)=-1.(dp(j,k)不可行.)那么对k的所有可能取值计算出dp(m,k)(-20*m <= k <= 20*m),就可以找到陪审团人选了。

  递推关系的建立:dp(j,k)由某个可行的方案dp(j-1,x)加入一个候选人得来。dp(j-1,x)能够推出dp(j,k)的必要条件是,存在某个i,在方案dp(j-1,x)中没有被选,且x+v(i)=k.在满足条件的所有dp(j-1,x)方案和i中,选出dp(j-1,x)+s(i)最大的那一个。

  需要把每个方案选择了哪些人记录下来。将每次最后选中的那个i记录在path[j][k]中,那么方案dp(j,k)选的倒数第二个人即path[j-1][k-v[path[j][k]]].由此回溯课找到所有被选中的候选人。

  初始条件:dp(0,0)=0,其它都赋为-1,逐步递推,丢出dp(m,k),这里的k的取值范围是[-20*m, 20*m],而m的最大值为20.为了方便,可以将k正向平移400,把k的取值区间映射成非负数,这样就避免了dp数组下标为负的问题。

  DP完成之后,查找dp表第m行中第一个可行解即可。

  再获得最终方案的控辩差和控辩和后,辩方和和控方和可由如下公式求得:

  D+P=dp(m,|D-P|),

  D=(D+P+|D-P|)/2, P=(D+P-|D-P|)/2.由于之前对D-P进行了平移,计算时要注意处理平移带来的影响。

 1 //////////////////////////////////////////////////////////////////////////
 2 //        POJ1015 Jury Compromise
 3 //        Memory: 424K        Time: 16MS
 4 //        Language: C++        Result: Accepted
 5 //////////////////////////////////////////////////////////////////////////
 6 
 7 #include <iostream> 
 8 #include <algorithm>
 9 
10 using namespace std;
11 
12 int n, m;
13 int d[201], p[201], v[201], s[201];
14 int dp[21][801];
15 int path[21][801];
16 int id[20];
17 
18 bool selected(int j, int k, int i) {
19     while (j > 0 && path[j][k] != i) {
20         k -= v[path[j][k]];
21         --j;
22     }
23     return j ? false : true;
24 }
25 
26 int main(void) {
27     int caseNo = 0;
28     while (true) {
29         cin >> n >> m;
30         if (n == 0) {
31             break;
32         }
33         ++caseNo;
34         for (int i = 1; i <= n; ++i) {
35             cin >> d[i] >> p[i];
36             v[i] = d[i] - p[i];
37             s[i] = d[i] + p[i];
38         }
39         memset(dp, -1, sizeof(dp));  
40         memset(path, 0, sizeof(path));
41         int fix = 20 * m;
42         dp[0][fix] = 0;
43         for (int j = 1; j <= m; ++j) {
44             for (int k = 0; k <= 2 * fix; ++k) {
45                 if (dp[j - 1][k] >= 0) {
46                     for (int i = 1; i <= n; ++i) {
47                         if (dp[j][k + v[i]] < dp[j - 1][k] + s[i]) {
48                             if (selected(j - 1, k, i)) {
49                                 dp[j][k + v[i]] = dp[j - 1][k] + s[i];
50                                 path[j][k + v[i]] = i;
51                             }
52                         }
53                     }
54                 }
55             }
56         }
57         int minDiff;
58         for (minDiff = 0; minDiff <= fix; ++minDiff) {
59             if (dp[m][fix + minDiff] != -1 || dp[m][fix - minDiff]!= -1) {
60                 break;
61             }
62         }
63         int minV = dp[m][fix - minDiff] > dp[m][fix + minDiff] ? fix - minDiff : fix + minDiff;
64         cout << "Jury #" << caseNo << endl;  
65         cout << "Best jury has value ";  
66         //辩方总值 = (辨控和 + 辨控差 + 修正值)/ 2  
67         cout << (dp[m][minV] + minV - fix) / 2 << " for prosecution and value ";  
68         //控方总值 = (辨控和 - 辨控差 + 修正值)/ 2  
69         cout << (dp[m][minV] - minV + fix) / 2 << " for defence:" << endl;  
70         for (int j = m, k = minV, i = 0; i < m; ++i) {
71             id[i] = path[j][k];
72             k -= v[path[j][k]];
73             --j;
74         }
75         sort(id, id + m);
76         for (int i = 0; i < m; ++i) {
77             cout << " " << id[i];
78         }
79         cout << endl << endl;
80     }
81     system("pause");
82     return 0;
83 }
View Code
posted @ 2013-07-31 14:09  小菜刷题史  阅读(225)  评论(0编辑  收藏  举报