感觉此题略难。。。。。。
背包问题。据说有一种二维DP的写法是错的。亲测,背包做法无误。
dp[i][j][k]表示前i个物品,选择j个,差值为k的情况下获得的最大总和
dp[i][j][k]=max(dp[i-1][j][k],dp[i-1][j-1][k-差]+和) 即第i个物品用或者不用。
DP完成之后,在表中寻找一下最优解即可。
#include<cstdio> #include<cstring> #include<cmath> #include<stack> #include<vector> #include<string> #include<iostream> #include<algorithm> using namespace std; struct Path { // int a,b,c; int w; } path[200+20][20+20][1000+20]; int dp[200+20][20+20][1000+20]; int p[200+20],d[200+20]; int n,m; stack<int>S; int Z=400; int main() { int Case=1; while(~scanf("%d%d",&n,&m)) { if(!n&&!m) break; for(int i=1; i<=n; i++) scanf("%d%d",&p[i],&d[i]); memset(dp,-1,sizeof dp); dp[0][0][Z]=0; for(int i=0; i<=n; i++) for(int j=0; j<=m; j++) for(int k=0; k<=2*Z; k++) path[i][j][k].w=-1; for(int i=1; i<=n; i++) { for(int j=0; j<=m; j++) { for(int k=Z*2; k-(p[i]-d[i])>=0; k--) { if(dp[i-1][j][k]!=-1) { dp[i][j][k]=dp[i-1][j][k]; path[i][j][k].w=0; } if(j>=1&&dp[i-1][j-1][k-(p[i]-d[i])]!=-1) { if(dp[i-1][j-1][k-(p[i]-d[i])]+p[i]+d[i]>dp[i][j][k]) { dp[i][j][k]=dp[i-1][j-1][k-(p[i]-d[i])]+p[i]+d[i]; path[i][j][k].w=1; } } } } } int posa,posb,posc; int Max=-1; for(int i=0; i<=Z; i++) { for(int j=1; j<=n; j++) if(dp[j][m][Z+i]>Max&&path[j][m][Z+i].w==1) Max=dp[j][m][Z+i],posa=j,posb=m,posc=Z+i; for(int j=1; j<=n; j++) if(dp[j][m][Z-i]>Max&&path[j][m][Z-i].w==1) Max=dp[j][m][Z-i],posa=j,posb=m,posc=Z-i; if(Max!=-1) break; } while(!S.empty()) S.pop(); int ans1,ans2; ans1=(posc-Z+dp[posa][posb][posc])/2; ans2=ans1-(posc-Z); while(1) { if(path[posa][posb][posc].w==-1) break; if(path[posa][posb][posc].w!=-1) { int Newa,Newb,Newc; if(path[posa][posb][posc].w==1) { S.push(posa); Newa=posa-1; Newb=posb-1; Newc=posc-(p[posa]-d[posa]); } else { Newa=posa-1; Newb=posb; Newc=posc; } posa=Newa; posb=Newb; posc=Newc; } } printf("Jury #%d ",Case++); printf("Best jury has value %d for prosecution and value %d for defence: ",ans1,ans2); while(!S.empty()) { printf(" %d",S.top()); S.pop(); } printf(" "); } return 0; }