poj1015

题意:从n个人中选出m个,每个人有固定的p值,d值,要求使m个人的p总和和d总和的差的绝对值最小,若有多解则取两者和最大的。

分析: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]}

View Code
#include <iostream>
#include
<cstdio>
#include
<cstdlib>
#include
<cstring>
#include
<algorithm>
usingnamespace std;

#define maxn 205
#define maxm 25

int n, m, w;
int f[maxm][maxn *10];
int p[maxn], d[maxn];
int path[maxm][maxn *10];
bool vis[maxn];
int stk[maxn];

void input()
{
for (int i =0; i < n; i++)
scanf(
"%d%d", &p[i], &d[i]);
}

void getpath(int i, int j)
{
memset(vis,
0, sizeof(vis));
while (path[i][j] !=-1)
{
int k = path[i][j];
vis[k]
=true;
i
--;
j
-= p[k] - d[k];
}
}

void make(int i, int j, int k)
{
int a = p[k] + d[k];
int b = p[k] - d[k];
if (f[i +1][j + b] ==-1|| f[i +1][j + b] < f[i][j] + a)
{
f[i
+1][j + b] = f[i][j] + a;
path[i
+1][j + b] = k;
return;
}
}

void work()
{
w
= m *20;
memset(f,
-1, sizeof(f));
memset(path,
-1, sizeof(path));
f[
0][w] =0;
for (int i =0; i < m; i++)
for (int j =0; j <=2* w; j++)
if (f[i][j] !=-1)
{
getpath(i, j);
for (int k =0; k < n; k++)
if (!vis[k])
make(i, j, k);
}
int d1 =-1, d2 =-1, dd;
for (int i =0; i <= w; i++)
if (f[m][w + i] !=-1)
{
d1
= i;
break;
}
for (int i =0; i <= w; i++)
if (f[m][w - i] !=-1)
{
d2
= i;
break;
}
if (d1 ==-1|| (d2 < d1 && d2 !=-1))
dd
= w - d2;
elseif (d2 ==-1|| (d1 < d2 && d1 !=-1))
dd
= w + d1;
elseif (f[m][w + d1] > f[m][w - d2])
dd
= w + d1;
else
dd
= w - d2;
int a = f[m][dd];
int b = dd - w;
int ansp = (a + b) /2;
int ansd = (a - b) /2;
printf(
"Best jury has value %d for prosecution and value %d for defence:\n", ansp, ansd);
int top =0;
a
= m;
b
= dd;
while (path[a][b] !=-1)
{
int k = path[a][b];
stk[top
++] = k;
a
--;
b
-= p[k] - d[k];
}
sort(stk, stk
+ top);
for (int i =0; i < top; i++)
printf(
" %d", stk[i] +1);
putchar(
'\n');
putchar(
'\n');
}

int main()
{
//freopen("t.txt", "r", stdin);
int t =0;
while (scanf("%d%d", &n, &m), n | m)
{
t
++;
printf(
"Jury #%d\n", t);
input();
work();
}
return0;
}
posted @ 2011-07-21 20:48  金海峰  阅读(2884)  评论(0编辑  收藏  举报