首页 > 代码库 > poj1015
poj1015
题意:n个人,每个人都可以看做有两个参数a,b,从中选m个人,使得ans1=|sigma(a)-sigma(b)|尽可能小,如果存在相等的情况,就保留ans2=sigma(a+b)max。
dp;
dp[j][k]表示选第j个人,使得ans1=k时,最大的ans2;
path[j][k]表示选第j个且ans1=k时的编号//记录路径
v=a-b;s=a+b;
dp[j][k+v[i]]=max(dp[j-1][k]+s[i]);if(dp[j-1][k]>=0 && i not in path[j-1][k])
************************************************************
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=1000;
int n,m,P,cas=0;
int a[maxn],b[maxn];
int v[maxn],s[maxn],ans[maxn];
int dp[maxn][maxn],path[maxn][maxn];
void input()
{
for(int i=1;i<=n;i++)
{
scanf("%d%d",&a[i],&b[i]);
v[i]=a[i]-b[i];
s[i]=a[i]+b[i];
}
}
bool ok(int x,int p,int q)
{
while(path[p][q]!=x && p)
{
q-=v[path[p][q]];
p--;
}
return p ? 0 : 1;
}
void do_dp()
{
memset(dp,-1,sizeof(dp));
memset(path,0,sizeof(path));
dp[0][P=20*m]=0;
//printf("P=%d\n",P);
for(int j=1;j<=m;j++)
for(int k=0;k<=P*2;k++)
for(int i=1;i<=n;i++)
if(dp[j-1][k]>=0 && dp[j][k+v[i]]<dp[j-1][k]+s[i] && ok(i,j-1,k))
{
dp[j][k+v[i]]=dp[j-1][k]+s[i];
path[j][k+v[i]]=i;
}
}
void output()
{
int p=0;
for(int i=0;i<=P;i++)
if(dp[m][P+i]>=0 || dp[m][P-i]>=0)
{
p = dp[m][P+i] > dp[m][P-i] ? (P+i) : (P-i);
break;
}
//printf("p=%d\n",p);
memset(ans,0,sizeof(ans));
int tmp=m;
while(tmp)
{
ans[tmp]=path[tmp][p];
p-=v[path[tmp][p]];
tmp--;
}
sort(ans+1,ans+1+m);
int ans1=0,ans2=0;
for(int i=1;i<=m;i++)ans1+=a[ans[i]],ans2+=b[ans[i]];
printf("Jury #%d \n",++cas);
printf("Best jury has value %d for prosecution and value %d for defence: \n",ans1,ans2);
for(int i=1;i<=m;i++)printf(" %d",ans[i]);
printf("\n");
}
int main()
{
//freopen("in.txt","r",stdin);
while(~scanf("%d%d",&n,&m) && (n || m))
{
input();
do_dp();
output();
}
return 0;
}
************************************************************