[POJ 1015] Jury Compromise
https://vjudge.net/problem/POJ-1015
题意:
现有\(n\)个人,每个人都有\(p\)值和\(d\)值,现在要选\(k\)个人,先要让他们的\(p\)值和与\(d\)值和的差最小,再让他们的\(p\)值和与\(d\)值和的和最大,并从小到大输出你选的人。
思路:
考虑\(dp[j][w]\),代表选了\(j\)个人,\(p\)值和与\(d\)值和的差为\(w\)时,\(p\)值和与\(d\)值和的和最大值。因为存在负值,所以我们将\(0\)置为\(400\),便于计算。注意\(dp\)转移时,第一维应该为第\(i\)个人,下面选择让他加不加入。听说如果我们第一维枚举选择的人数,当存在多种情况相同时,可能会对最终答案造成影响。例如我们选择\(1\)、\(3\)、\(5\)和\(2\)、\(4\)、\(6\)时,他们最后的值都相同,那么\(2\)、\(4\)、\(6\)的方案可能会覆盖掉\(1\)、\(3\)、\(5\),但如果最终答案应该是\(1\)、\(3\)、\(5\)、\(6\)时,我们就找不到这种情况了。前面不会被后面覆盖的情况亦然。UVA上的题目好像加了这种样例,但是我找了半天样例没搞出来,十分痛苦。
https://vjudge.net/problem/UVA-323
#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
const int N = 27;
const int inf = 0x3f3f3f3f;
int dp[N][N * 40];
int d[207], p[207];
int n, k, cas;
int D, P;
int sta[N], tot;
vector<int> path[N][N * 40];
void gao(int w) {
for (int i = 0; i < path[k][w].size(); ++i) {
int v = path[k][w][i];
P += p[v];
D += d[v];
sta[++tot] = v;
}
printf("Best jury has value %d for prosecution and value %d for defence:\n", P, D);
for (int i = 1; i <= tot; ++i) {
printf(" %d", sta[i]);
}
puts("");
}
void solve() {
for (int i = 1; i <= n; ++i) {
scanf("%d %d", &p[i], &d[i]);
}
for (int i = 0; i <= 20; ++i) {
for (int j = 0; j <= 800; ++j) {
path[i][j].clear();
}
}
for (int i = 1; i <= n; ++i) {
for (int j = min(i, k); j >= 1; --j) {
for (int w = 0; w <= 800; ++w) {
int v = w - (d[i] - p[i]);
if (v < 0 || v > 800) continue;
if (dp[j][w] < dp[j - 1][v] + d[i] + p[i]) {
path[j][w] = path[j - 1][v];
path[j][w].push_back(i);
dp[j][w] = dp[j - 1][v] + d[i] + p[i];
}
}
}
}
printf("Jury #%d\n", ++cas);
for (int w = 0; w <= 400; ++w) {
if (dp[k][400 - w] >= 0 && dp[k][400 + w] >= 0) {
if (dp[k][400 - w] > dp[k][400 + w]) gao(400 - w);
else gao(400 + w);
return;
}
if (dp[k][400 - w] >= 0) {
gao(400 - w);
return;
}
if (dp[k][400 + w] >= 0) {
gao(400 + w);
return;
}
}
}
int main() {
while (~scanf("%d %d", &n, &k), n | k) {
memset(dp, -inf, sizeof(dp));
dp[0][400] = 0;
D = 0;
P = 0;
tot = 0;
solve();
puts("");
}
return 0;
}