题意:给你n个数对(d, p),挑选出m个,使得sigma(d)与sigma(p)的差最小,如果有多种选法,选sigma(d)+sigma(p)最大的
设dp(i,j)表示选出i个人,差值为j时sigma(d)+sigma(p)的最大值,初始为-1,那么最后的答案就是使得dp(m,j)>=0的j的最小值。那么如何求dp(i,j)呢?肯定是在选出m-1个人的基础上再选一个人。设是在dp(i-1,x)的基础上选出的,那么必须要存在一个数对满足x+d-p=j且这个数对没有在dp(i-1,x)方案中出现过。那么如何知道有没有出现过呢?可以用数组path[i][j]表示方案dp(i,j)在dp(i-1,x)基础上再选出的那个人的编号。所以可以从path[i][j]往回寻找方案中所有已经被选过的人,排除即可。最后需要注意的就是差值会小于0,给它加上一个修正值fix,变成非负数就行了。
1 #include <iostream> 2 #include <sstream> 3 #include <fstream> 4 #include <string> 5 #include <map> 6 #include <vector> 7 #include <list> 8 #include <set> 9 #include <stack> 10 #include <queue> 11 #include <deque> 12 #include <algorithm> 13 #include <functional> 14 #include <numeric> 15 #include <iomanip> 16 #include <climits> 17 #include <new> 18 #include <utility> 19 #include <iterator> 20 #include <complex> 21 #include <cstdio> 22 #include <cstdlib> 23 #include <cstring> 24 #include <cctype> 25 #include <cmath> 26 #include <ctime> 27 using namespace std; 28 29 const int maxn = 210; 30 const int maxm = 25; 31 const int fix = 400; 32 33 int n, m; 34 int d[maxn], p[maxn]; 35 int dp[maxm][2*fix+10]; 36 int path[maxm][2*fix+10]; 37 int ans[maxm]; 38 39 int main() 40 { 41 int kase = 1; 42 while (scanf("%d%d", &n, &m) == 2 && (n || m)) 43 { 44 for (int i = 0; i < n; ++i) 45 scanf("%d%d", &d[i], &p[i]); 46 memset(dp, -1, sizeof(dp)); 47 memset(path, 0, sizeof(path)); 48 dp[0][fix] = 0; 49 for (int i = 0; i < m; ++i) 50 for (int j = 0; j < 2*fix+10; ++j) 51 if (dp[i][j] >= 0) 52 for (int k = 0; k < n; ++k) 53 if (dp[i][j]+d[k]+p[k] > dp[i+1][j+d[k]-p[k]]) 54 { 55 int ti = i, tj = j; 56 while (ti > 0 && path[ti][tj] != k) 57 { 58 tj -= d[path[ti][tj]] - p[path[ti][tj]]; 59 ti--; 60 } 61 if (!ti) 62 { 63 dp[i+1][j+d[k]-p[k]] = dp[i][j] + d[k] + p[k]; 64 path[i+1][j+d[k]-p[k]] = k; 65 } 66 } 67 int dj = 0; 68 while (dp[m][fix-dj] == -1 && dp[m][fix+dj] == -1) 69 dj++; 70 int k = dp[m][fix-dj] > dp[m][fix+dj] ? fix-dj : fix+dj; 71 printf("Jury #%d ", kase++); 72 printf("Best jury has value %d for prosecution and value %d for defence: ", (k-fix+dp[m][k])/2, (dp[m][k]-k+fix)/2); 73 for (int i = 0; i < m; ++i) 74 { 75 ans[i] = path[m-i][k]; 76 k -= d[ans[i]] - p[ans[i]]; 77 } 78 sort(ans, ans+m); 79 for (int i = 0; i < m; ++i) 80 printf("%d%c", ans[i]+1, i==m-1?' ':' '); 81 } 82 return 0; 83 }