• 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
  • 相关阅读:
    Creating A Moddable Unity Game
    C# 动态编译
    编程题:求一个矩阵中最大的二维子矩阵(即二维子矩阵的和最大)好未来
    编程题:求单链表倒数第k位的值(最后一位为倒数第0位)好未来
    Docker执行错误报错--Error response from daemon: No command specified
    suse下静默方式安装oracle(无图形界面)
    无法删除oracle用户的问题
    Python正则表达式
    Linux密码复杂度问题
    编程练习:实现树的层次遍历 (CVTE笔试)
  • 原文地址:https://www.cnblogs.com/dengeven/p/3227681.html
Copyright © 2020-2023  润新知