题目链接: http://poj.org/problem?id=1015
分析: (参考于: http://blog.csdn.net/lyy289065406/article/details/6671105 )
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <string>
#include <cstring>
#include <algorithm>
#include <iomanip>
#include <vector>
using namespace std;
const int inf = 0x7FFFFFFF;
const int maxn = 1000;
struct node{
int p,d;
void read(){
scanf("%d%d",&p,&d);
}
}f[205];
int cnt[25][805];
int dp[25][805]; ///dp[j][k]表示 选j个,差为k(+400) 的最大和
void Init(){
memset(cnt,0,sizeof(cnt));
memset(dp,-1,sizeof(dp));
dp[0][400]=0;
}
bool Is_used(int i,int j,int k){ ///是否已选
while(j&&cnt[j][k]!=i){
int t=cnt[j][k];
--j;
k-=(f[t].p-f[t].d);
}
return j?true:false;
}
int main(){
//freopen("C:\\Users\\DGP\\Desktop\\in.txt","r",stdin);
//freopen("C:\\Users\\DGP\\Desktop\\out.txt","w",stdout);
int n,m,cas=1;
while(~scanf("%d%d",&n,&m),n+m){ if(cas>33)break;
for(int i=1;i<=n;++i)
f[i].read();
Init();
for(int j=1; j<=m; j++)
for(int k=0; k<=800; k++)
if(dp[j-1][k]>=0) ///区间已平移,dp[0][fix]才是真正的dp[0][0]
for(int i=1; i<=n; i++) {
int c=f[i].p-f[i].d;
int s=f[i].p+f[i].d;
if(dp[j][k+c]<dp[j-1][k]+s)
if(!Is_used(i,j-1,k)){
dp[j][k+c]=dp[j-1][k]+s;
cnt[j][k+c]=i;
}
}
int i=0;
while(dp[m][400+i]==-1&&dp[m][400-i]==-1) ++i;
int q=dp[m][400-i]>dp[m][400+i]?400-i:400+i;
int a=(dp[m][q]+q-400)/2;
int b=(dp[m][q]-q+400)/2;
printf("Jury #%d\n",cas++);
printf("Best jury has value %d for prosecution and value %d for defence:\n",a,b);
int h[20],t;
i=0;
while(cnt[m][q]){
h[i++]=t=cnt[m][q];
--m;
q-=(f[t].p-f[t].d);
}
sort(h,h+i);
for(int j=0;j<i;++j)
printf(" %d",h[j]);
puts("");
}
return 0;
}