问题重述:
在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代码
//Memory: 380K Time: 79MS #include <iostream> #include <cstring> #include <cstdio> #include <algorithm> using namespace std; ][]; ][]; int n, m; ], d[]; ; ]; bool findPath(int n, int s, int target) { ) return false; if (target == prior[n][s + offset]) return true; int p = prior[n][s + offset]; , s - (d[p] - q[p]), target); } void output(int ans) { ; j--) { r[j - ] = prior[j][ans + offset]; int p = prior[j][ans + offset]; ans -= (d[p] - q[p]); } sort(r, r + m); ; i < m; i++) cout << " " << r[i]; cout << endl << endl; } int main() { ; while ( cin >> n >> m && n ) { ; i <= n; i++) cin >> d[i] >> q[i]; memset(dp, -, sizeof(dp)); memset(prior, , sizeof(prior)); dp[][offset] = ; ; i <= m; i++) { ; j <= n; j++) { int ss = d[j] + q[j]; int dd = d[j] - q[j]; ; s <= ; s++) { || s - dd > ) continue; ][s - dd + offset] != - && dp[i - ][s - dd + offset] + ss > dp[i][s + offset] && !findPath(i - , s - dd, j)) { dp[i][s + offset] = dp[i - ][s - dd + offset] + ss; prior[i][s + offset] = j; } } } } ; i <= ; i++) { && dp[m][offset - i] == -) continue; int ans = dp[m][offset + i] > dp[m][offset - i] ? i : -i; ; ; cout << "Jury #" << cas++ << endl; cout << "Best jury has value " << sd << " for prosecution and value " << sq << " for defence:" << endl; output(ans); break; } } ; }