POJ 015 Jury Compromise
题意:从n个人中选出m个,每个人有固定的p值,d值,要求使m个人的p总和和d总和的差的绝对值最小,若有多解则取两者和最大的。
分析:dp[i][j]表示在选m个人中的第i个人的时候使所有已选中的人的b,p差为j时,所能获得的b,p最大和。
dp[i + 1][j + b[k] - p[k]] = dp[i][j] + b[k] + p[k];(要求k之前没有选过,要查看[i][j]的完整路径,确保无k)
填写完成后,观察找到最小差值,最大和。知道和差自然可以求出总的p,d。
View Code
#include<stdio.h> #include<string.h> #include<stdlib.h> #define clr(x)memset(x,0,sizeof(x)) #define max(a,b)(a)>(b)?(a):(b) int hu[31][805],dp[31][805]; int cmp(const void*p1,const void*p2) { return *(int*)p1-*(int*)p2; } struct node { int b,p; }q[205]; int n,m; void solve() { int i,j,k; int x,s; for(i=0;i<m;i++) for(j=0;j<=800;j++) for(k=1;k<=n;k++) { if(dp[i][j]<0) break; if(dp[i+1][j+q[k].b-q[k].p]<dp[i][j]+q[k].b+q[k].p) { s=j; for(x=i;x>0&&hu[x][s]!=k;x--) s-=q[hu[x][s]].b-q[hu[x][s]].p; if(x==0) { dp[i+1][j+q[k].b-q[k].p]=dp[i][j]+q[k].b+q[k].p; hu[i+1][j+q[k].b-q[k].p]=k; } } } } int res[205]; int main() { int ca=1,a,b,i,k; while(scanf("%d%d",&n,&m),n||m) { clr(hu); clr(res); memset(dp,0xff,sizeof(dp)); dp[0][400]=0; for(i=1;i<=n;i++) scanf("%d%d",&q[i].b,&q[i].p); solve(); for(k=0;dp[m][400+k]<0&&dp[m][400-k]<0;k++); int tt=dp[m][400+k]>dp[m][400-k]?400+k:400-k; a=b=0; for(i=0;i<m;i++) { res[i]=hu[m-i][tt]; a+=q[res[i]].b; b+=q[res[i]].p; tt-=q[res[i]].b-q[res[i]].p; } qsort(res,m,sizeof(res[0]),cmp); printf("Jury #%d\n",ca++); printf("Best jury has value %d for prosecution and value %d for defence:\n",a,b); for(i=0;i<m;i++) printf(" %d",res[i]); printf("\n"); } return 0; }