问题重述:
在n个候选者中选取m个人进入陪审团。每个候选者获得两项评分:D[j],P[j]。求解最佳评审团,使得在每个成员的两项评分和之差 最小的情况下,使得两项评分和之和 最大。
分析:
欲采用动态规划求解,必须先找到最优子结构。假如考虑评分差的绝对值,它的子问题并不一定是最优解。若考虑一定评分差下的评分和最大值,则拥有最优子结构。
用dp[i][j]表示在第i个评委评分后,评分差是j的最大评分和,得到递归公式:
dp[i][j] = max{ dp[ i - 1 ][ j - (D[i] - P[j]) ] + D[i] + P[j], dp[ i - 1 ][j] }
AC代码
1 //Memory: 380K Time: 79MS 2 #include <iostream> 3 #include <cstring> 4 #include <cstdio> 5 #include <algorithm> 6 7 using namespace std; 8 9 int dp[21][810]; 10 int prior[21][810]; 11 int n, m; 12 int q[201], d[201]; 13 const int offset = 405; 14 int r[21]; 15 16 bool findPath(int n, int s, int target) 17 { 18 if (n == 0) return false; 19 if (target == prior[n][s + offset]) return true; 20 int p = prior[n][s + offset]; 21 return findPath(n - 1, s - (d[p] - q[p]), target); 22 } 23 24 void output(int ans) 25 { 26 for (int j = m ; j >= 1; j--) { 27 r[j - 1] = prior[j][ans + offset]; 28 int p = prior[j][ans + offset]; 29 ans -= (d[p] - q[p]); 30 } 31 sort(r, r + m); 32 for (int i = 0; i < m; i++) 33 cout << " " << r[i]; 34 cout << endl << endl; 35 } 36 37 int main() 38 { 39 int cas = 1; 40 while ( cin >> n >> m && n ) { 41 for (int i = 1; i <= n; i++) 42 cin >> d[i] >> q[i]; 43 memset(dp, -1, sizeof(dp)); 44 memset(prior, 0, sizeof(prior)); 45 dp[0][offset] = 0; 46 47 for (int i = 1; i <= m; i++) { 48 for (int j = 1; j <= n; j++) { 49 int ss = d[j] + q[j]; 50 int dd = d[j] - q[j]; 51 for (int s = -400; s <= 400; s++) { 52 if (s - dd < -400 || s - dd > 400) continue; 53 if (dp[i - 1][s - dd + offset] != -1 && dp[i - 1][s - dd + offset] + ss > dp[i][s + offset] && !findPath(i - 1, s - dd, j)) { 54 dp[i][s + offset] = dp[i - 1][s - dd + offset] + ss; 55 prior[i][s + offset] = j; 56 } 57 } 58 } 59 } 60 for (int i = 0; i <= 400; i++) { 61 if (dp[m][offset + i] == -1 && dp[m][offset - i] == -1) continue; 62 63 int ans = dp[m][offset + i] > dp[m][offset - i] ? i : -i; 64 65 int sd = (dp[m][ans + offset] + ans) / 2; 66 int sq = (dp[m][ans + offset] - ans) / 2; 67 68 cout << "Jury #" << cas++ << endl; 69 cout << "Best jury has value " << sd << " for prosecution and value " 70 << sq << " for defence:" << endl; 71 output(ans); 72 break; 73 } 74 } 75 return 0; 76 }
POJ1015 动态规划
时间: 2024-10-07 07:36:34