(poj.org issue. Not submitted yet)
This is a 2D DP problem, very classic too. Since I'm just learning, so I took this link as reference:
http://blog.csdn.net/lyy289065406/article/details/6671105
1. It is a little tricky to pick dependent values for this DP. Again, just think about how you are going to expand this reel gradually. We pick number of chosen persons and min|D-P|
2. Back-tracing is used to trace paths.
3. Take care of details.
#include <stdio.h> #include <stdlib.h> #include <memory.h> #include <algorithm> #define MAX_NUM 400 #define MAX_CNT 20 // info per candidate int pdiff[MAX_CNT + 1]; int psum[MAX_CNT + 1]; int rpath[MAX_CNT]; // runtime int dp[MAX_CNT + 1][MAX_NUM * 2 + 1]; // with offset int path[MAX_CNT + 1][MAX_NUM * 2 + 1]; // with offset void Reset() { memset( dp, -1, sizeof(int) * ((MAX_NUM * 2 + 1) * (MAX_CNT + 1))); memset(path, -1, sizeof(int) * ((MAX_NUM * 2 + 1) * (MAX_CNT + 1))); memset(rpath, -1, sizeof(int) * MAX_CNT); } // Backtrace: is i selected in dp[p][k]? bool select(int i, int p, int k) { while (p > 0 && path[p][k] != i) { k -= pdiff[path[p][k]]; p--; } return p ? true : false; } void best_jury(int n, int m, int cnt, int *pd, int *ps) { Reset(); int fix = m * 20; dp[0][fix] = 0; for (int p = 1; p <= m; p ++) // each selected m of dp for (int k = 0; k <= fix * 2; k ++) // each hit sum(v) of dp { if (dp[p-1][k] < 0) continue; for (int i = 0; i < n; i ++) // each one { // Remember: value of dp[][] is sum(sum) int newk = dp[p - 1][k] + psum[i]; if (newk > dp[p][k + pdiff[i]]) { if (!select(i, p - 1, k)) { // Remember: // p -> candicate index // k.. -> current sum(diff) dp[p][k + pdiff[i]] = newk; path[p][k + pdiff[i]] = i; // printf("- put %d @ %d, %ds\n", i, p, k + pdiff[i]); } } } } // Get min sum(diff) int k = -1; for (int i = 0; i < fix; i++) { int v0 = dp[m][fix - i]; int v1 = dp[m][fix + i]; if (v0 > 0 || v1 > 0) { k = i; break; } } int minSumDiff = dp[m][fix - k] > dp[m][fix + k] ? (fix - k) : (fix + k); // pick the bigger sum one int ttlDiff = (dp[m][minSumDiff] + minSumDiff - fix) / 2; int ttlSum = (dp[m][minSumDiff] - minSumDiff + fix) / 2; // printf("Jury #%d\n", cnt); printf("Best jury has value %d for prosecution and value %d for defence:\n", ttlDiff, ttlSum); // Output selected in order int tmpk = minSumDiff; int id_inx = 0; while (m > 0 && path[m][tmpk] >= 0) { rpath[id_inx++] = path[m][tmpk]; tmpk -= pdiff[path[m][tmpk]]; m--; } std::sort(rpath, rpath + id_inx); for (int i = 0; i < id_inx; i ++) { printf(" %d", rpath[i] + 1); // real inx starting from 1 } printf("\n\n"); } int main() { int m, n, cnt = 0; int pi[MAX_NUM]; int di[MAX_NUM]; while ( scanf("%d", &n), scanf("%d", &m), cnt ++, (m != 0) && (n != 0) ) { // Get Input for (int i = 0; i < n; i ++) { scanf("%d%d", pi + i, di + i); pdiff[i] = pi[i] - di[i]; psum[i] = pi[i] + di[i]; } // Reset(); best_jury(n, m, cnt, pdiff, psum); } return 0; }