poj 1015 Jury Compromise(DP)

题意:

思路:

 

  1 #include<cstring>
  2 #include<iostream>
  3 #include<cmath>
  4 #include<algorithm>
  5 using namespace std;
  6 
  7 int n;  //候选人数
  8 int m;  //当选人数
  9 int dp[21][801];   //dp[j][k]:取j个候选人,使其辩控差为k的所有方案中,辩控和最大的方案的辩控和
 10 int path[21][801];  //记录所选定的候选人的编号
 11 int p[222];  //每个人的控方值
 12 int d[222];  //每个人的辩方值
 13 int s[222];  //每个人的辨控和
 14 int v[222];  //每个人的辨控差
 15 int id[222]; //保存候选人编号
 16 
 17 /*检查dp[j][k]方案是否曾选择过候选人i*/
 18 bool check(int j, int k, int i, int* v)
 19 {
 20     while (j>0 && path[j][k] != i)
 21     {
 22         k -= v[path[j][k]];
 23         j--;
 24     }
 25     return j ? false : true;
 26 }
 27 
 28 void init()
 29 {
 30     memset(dp, -1, sizeof(dp));
 31     memset(path, 0, sizeof(path));
 32     memset(p, 0, sizeof(p));
 33     memset(d, 0, sizeof(d));
 34     memset(s, 0, sizeof(s));
 35     memset(v, 0, sizeof(v));
 36 }
 37 
 38 int main()
 39 {
 40     int time = 1;
 41     while (cin >> n >> m && n)
 42     {
 43         /*Initial*/
 44         int j, k, i;
 45         init();
 46         /*Input*/
 47         for (i = 1; i <= n; i++)
 48         {
 49             cin >> p[i] >> d[i];
 50             s[i] = p[i] + d[i];
 51             v[i] = p[i] - d[i];
 52         }
 53         int fix = m * 20;  //总修正值,修正极限为从[-400,400]映射到[0,800]
 54 
 55         dp[0][fix] = 0;   //由于修正了数值,因此dp[0][fix]才是真正的dp[0][0]
 56         for (j = 1; j <= m; j++)
 57             for (k = 0; k <= 2 * fix; k++) //可能的辩控差为[0,fix*2] 
 58             {
 59                 if (dp[j - 1][k] >= 0)   //区间已平移,dp[0][fix]才是真正的dp[0][0]
 60                 {
 61                     for (i = 1; i <= n; i++)
 62                         if (dp[j][k + v[i]] < dp[j - 1][k] + s[i])
 63                         {
 64                             if (check(j - 1, k, i, v))
 65                             {
 66                                 dp[j][k + v[i]] = dp[j - 1][k] + s[i];
 67                                 path[j][k + v[i]] = i;
 68                             }
 69                         }
 70                 }
 71             }
 72 
 73 
 74         /*Output*/
 75         for (k = 0; k <= fix; k++)
 76             if (dp[m][fix - k] >= 0 || dp[m][fix + k] >= 0)    //从中间向两边搜索最小辨控差的位置k
 77                 break;
 78         int div = dp[m][fix - k] > dp[m][fix + k] ? (fix - k) : (fix + k);  //最小辨控差
 79 
 80         cout << "Jury #" << time++ << endl;
 81         cout << "Best jury has value ";
 82         //辩方总值 = (辨控和+辨控差+修正值)/2
 83         cout << (dp[m][div] + div - fix) / 2 << " for prosecution and value ";
 84         //控方总值 = (辨控和-辨控差+修正值)/2
 85         cout << (dp[m][div] - div + fix) / 2 << " for defence:" << endl;
 86 
 87         for (i = 0, j = m, k = div; i<m; i++)
 88         {
 89             id[i] = path[j][k];
 90             k -= v[id[i]];
 91             j--;
 92         }
 93         sort(id, id + m);   //升序输出候选人编号
 94         for (i = 0; i<m; i++)
 95             cout << ' ' << id[i];
 96         cout << endl << endl;
 97 
 98     }
 99     return 0;
100 }

 

posted @ 2015-03-27 17:09  UsedRose  阅读(192)  评论(0编辑  收藏  举报