poj1015 Jury Compromise
poj1015 Jury Compromise
https://vjudge.net/problem/POJ-1015
/* 直接上翻译吧 这是一道动态规划,请教了wmy学姐之后感觉有思路了 感觉和二维费用背包有点像 需要考虑的方面有 控辩和,控辩差,人数,组合路径 其中路径可以另外设一个path[i][j]表示使得[i][j]这个状态最优的上一个是谁 dp[i][j]=k表示选了i个人,总的控辩差是j的总控辩和是多少 最后找答案时只需找最接近需求值的j所对应的路径以及总控辩和差 */ #include<iostream> #include<cstring> #include<cstdio> #include<algorithm> using namespace std; #define maxn 205 #define maxm 25 int dp[maxm][maxn*10],path[maxm][maxn*10],n,m,a[maxn],b[maxn],Ans[maxn]; bool vis[220]; void up(int i,int j){ memset(vis,0,sizeof(vis)); while(path[i][j]!=-1){ int k=path[i][j]; vis[k]=1; i--;j-=a[k]-b[k]; } } void update(int i,int j,int k){ int x=a[k]+b[k]; int y=a[k]-b[k]; if(dp[i+1][j+y]==-1||(dp[i+1][j+y]<dp[i][j]+x)){ dp[i+1][j+y]=dp[i][j]+x; path[i+1][j+y]=k; } } int main(){ int T=0; while(1){ memset(dp,-1,sizeof(dp)); memset(path,-1,sizeof(path)); memset(a,0,sizeof(a)); memset(b,0,sizeof(b)); memset(Ans,0,sizeof(Ans)); scanf("%d%d",&n,&m); if(n==0&&m==0)return 0; T++; printf("Jury #%d \n",T); for(int i=0;i<n;i++)scanf("%d%d",&a[i],&b[i]); int w=20*m; dp[0][w]=0; for(int i=0;i<m;i++)for(int j=0;j<=w*2;j++) if(dp[i][j]!=-1){ up(i,j); for(int k=0;k<n;k++) if(!vis[k])update(i,j,k); } int d1=-1,d2=-1,ans; for(int i=0;i<=w;i++) if(dp[m][w+i]!=-1){d1=i;break;} for(int i=0;i<=w;i++) if(dp[m][w-i]!=-1){d2=i;break;} if(d1==-1||(d1>d2&&d2!=-1))ans=w-d2; else if(d2==-1||(d1<d2&&d1!=-1))ans=w+d1; else if(d1==d2&&dp[m][w+d1]>dp[m][w-d2])ans=w+d1; else ans=w-d2; int x=dp[m][ans],y=ans-w; int ans1=(x+y)/2,ans2=(x-y)/2; printf("Best jury has value %d for prosecution and value %d for defence:\n", ans1, ans2); int cnt=0; int u=m,v=ans; while(path[u][v]!=-1){ int k=path[u][v]; Ans[cnt++]=k; u--;v-=a[k]-b[k]; } sort(Ans,Ans+cnt); for (int i = 0; i < cnt; i++) printf(" %d", Ans[i] + 1); putchar('\n'); putchar('\n'); } return 0; }