poj1015 Jury Compromise
dp
本题为special judge,不需要考虑多解情况。
f[i][j]表示在选m个人中的选i个人的时候使所有已选中的人的p,d差为j时,所能获得的p,d最大和。
f[i + 1][j + p[k] - d[k]] = f[i][j] + p[k] + d[k];(要求k之前没有选过,要查看f[i][j]的完整路径,确保无k)
填写完成后,观察f[m]找到最小差值,最大和。知道和差自然可以求出总的p,d。
也可以用另一种方法:
三维f[i,j,k]表示前i取j差值为k的最大和
f[i,j,k]=max{f[i-1,j,k],f[i-1,j-1,k-s1[i]]+s2[i]}
我用的第一个:
/**
* Problem:POJ1015
* Author:Shun Yao
* Time:2013.6.2
* Result:Accepted
* Memo:DP
*/
#include <cstring>
#include <cstdio>
#include <algorithm>
long n, m, f[25][805], path[25][805], p[205], d[205], ans[205];
char vis[205];
int main() {
long i, j, k, t1, t2, tcase, w;
freopen("poj1015.in", "r", stdin);
freopen("poj1015.out", "w", stdout);
tcase = 0;
while (scanf("%ld%ld", &n, &m), n) {
w = m * 20;
for (i = 1; i <= n; ++i)
scanf("%ld%ld", p + i, d + i);
for (j = 0; j <= m; ++j) {
memset(f[j], 0xff, sizeof f[j]);
memset(path[j], 0, sizeof path[j]);
}
f[0][w] = 0;
for (j = 0; j < m; ++j)
for (k = 0; k <= (w << 1); ++k)
if (f[j][k] >= 0) {
memset(vis, 0, sizeof vis);
t1 = j;
t2 = k;
while (t1) {
vis[path[t1][t2]] = 1;
t2 -= p[path[t1][t2]] - d[path[t1][t2]];
--t1;
}
for (i = 1; i <= n; ++i)
if (!vis[i] && f[j + 1][k + p[i] - d[i]] < f[j][k] + p[i] + d[i]) {
f[j + 1][k + p[i] - d[i]] = f[j][k] + p[i] + d[i];
path[j + 1][k + p[i] - d[i]] = i;
}
}
i = w;
j = 0;
while (f[m][i - j] < 0 && f[m][i + j] < 0)
++j;
if (f[m][i - j] > f[m][i + j])
k = i - j;
else
k = i + j;
printf("Jury #%ld\n", ++tcase);
printf("Best jury has value %ld for prosecution and value %ld for defence:\n", (f[m][k] + k - w) >> 1, (f[m][k] - k + w) >> 1);
for (i = m; i >= 1; --i) {
ans[i] = path[i][k];
k -= p[ans[i]] - d[ans[i]];
}
std::sort(ans + 1, ans + m + 1);
for (i = 1; i <= m; ++i)
printf(" %ld", ans[i]);
puts("\n");
}
fclose(stdin);
fclose(stdout);
return 0;
}
作者:HSUPPR
出处:http://www.cnblogs.com/hsuppr/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出
原文链接,否则保留追究法律责任的权利。

浙公网安备 33010602011771号