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;
}
原文地址:https://www.cnblogs.com/hsuppr/p/3114380.html