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;

}

 

你可能感兴趣的:(Promise)