题目链接:http://poj.org/problem?id=1015
这道题是一个三维dp,用dp[i][j][k]记录前i个人中选j个人,辨控差是k的最大辩控和。网上还一种二维的方法,但正确性不好证明,而且复杂度是一样的,所以还是觉得这个方法好些。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<string>
#include<queue>
#include<algorithm>
#include<vector>
#include<stack>
#include<list>
#include<iostream>
#include<map>
using namespace std;
#define inf 0x3f3f3f3f
#define Max 110
int max(int a,int b)
{
return a>b?a:b;
}
int min(int a,int b)
{
return a<b?a:b;
}
int val[220],sum[220],a[220],b[220],rec[220][30][880],ans[30];
int dp[220][22][880];
int main()
{
int i,j,k,n,m,count=1,l;
while(scanf("%d%d",&n,&m),n|m)
{
for(i=1;i<=n;i++)
{
scanf("%d%d",&a[i],&b[i]);
val[i]=a[i]-b[i];
sum[i]=a[i]+b[i];
}
// memset(dp,-1,sizeof(dp));
for(k=0;k<=n;k++)
for(i=0;i<=m;i++)
for(j=0;j<=40*m;j++)
dp[k][i][j]=-inf;
dp[0][0][20*m]=0;
for(k=1;k<=n;k++)
{
for(i=0;i<=m;i++)
for(j=0;j<=40*m;j++)
{
dp[k][i][j]=dp[k-1][i][j];
//rec[k][i][j]=rec[k-1][i][j];
}
for(i=0;i<m;i++)
{
for(j=0;j<=40*m;j++)
{
if(j+val[k]<=40*m&&dp[k][i+1][j+val[k]]<dp[k-1][i][j]+sum[k])
{
dp[k][i+1][j+val[k]]=dp[k-1][i][j]+sum[k];
}
}
// printf("%d\n",dp[i+1][400]);
}
}
int minx=inf;
int tmp;
for(i=0;i<=20*m;i++)
{
if(dp[n][m][20*m+i]>=0)
{
tmp=20*m+i;
if(dp[n][m][20*m-i]>dp[n][m][20*m+i])
tmp=20*m-i;
break;
}
if(dp[n][m][20*m-i]>=0)
{
tmp=20*m-i;
break;
}
}
i=m;j=tmp;
int tmpi,tmpj;
k=0;
l=n;
while(i!=0)
{
// printf("pre %d %d rec %d\n",i,j,rec[i][j]);
if(dp[l-1][i][j]<dp[l-1][i-1][j-val[l]]+sum[l])
{
ans[k++]=l; j-=val[l];i--;
// printf("ans %d\n",ans[k-1]);
}
l--;
}
int lans=0,rans=0;
for(i=0;i<m;i++)
{
lans+=a[ans[i]];
rans+=b[ans[i]];
}
sort(ans,ans+m);
printf("Jury #%d\n",count++);
printf("Best jury has value %d for prosecution and value %d for defence:\n",lans,rans);
// printf("Jury #%d\nBest jury has value %d for prosecution and value %d for defence:\n",count++,lans,rans);
for(i=0;i<m;i++)
printf(" %d",ans[i]);
printf("\n\n");
// puts("");
//puts("");
}
}