题意:
思路:
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 }