题目链接: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(""); } }