传送门:http://poj.org/problem?id=1015
解题思路:
实现代码:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int MAXN=1000; const int INF=1<<30; int dp[30][MAXN],Path[30][MAXN]; int D[MAXN],P[MAXN]; /* dp[j][k]:选取第j个人(也就是总共选了j个人),其辩控差为k时,其辩方和空方的和。 为了防止k是负数,我们将k向右移动m×20 设我们选的第j个人的编号是i(1<=i<=m) dp[j][k]=max(dp[j][k],dp[j-1][k-P[i]+D[i]]+D[i]+P[i]; Path[j][k]:选择第j个人其辩控差为k在n个人中的编号 那么第j-1选择的人编号Path[j-1][k-D[Path[j][k]]+P[Pah[j][k]]] */ int main(){ int n,m; int iCase=0; while(scanf("%d%d",&n,&m)!=EOF||(n!=0&&m!=0)){ for(int i=1;i<=n;i++) scanf("%d%d",&P[i],&D[i]); int IMAX=m*20; memset(dp,-1,sizeof(dp)); memset(Path,0,sizeof(Path)); dp[0][IMAX]=0; for(int j=0;j<m;j++){ for(int k=0;k<=IMAX*2;k++){ if(dp[j][k]>=0){ for(int i=1;i<=n;i++){ if(dp[j][k]+D[i]+P[i]>dp[j+1][k+P[i]-D[i]]){ int t1=j,t2=k; while(t1>0&&Path[t1][t2]!=i){ t2-=P[Path[t1][t2]]-D[Path[t1][t2]]; t1--; } if(t1==0){ dp[j+1][k+P[i]-D[i]]=dp[j][k]+D[i]+P[i]; Path[j+1][k-D[i]+P[i]]=i; } } } } } } int i=IMAX; int j=0; int k; while(dp[m][i-j]<0&&dp[m][i+j]<0) j++; if(dp[m][i+j]>dp[m][i-j]) k=i+j; else k=i-j; printf("Jury #%d ",++iCase); printf("Best jury has value %d for prosecution and value %d for defence: ",(k-IMAX+dp[m][k])/2,(dp[m][k]-k+IMAX)/2); int Answer[MAXN]; for(i=0;i<m;i++){ Answer[i]=Path[m-i][k]; k-=P[Answer[i]]-D[Answer[i]]; } sort(Answer,Answer+m); for(i=0;i<m;i++) printf(" %d",Answer[i]); printf(" "); } }