poj1015 Jury Compromise---背包问题变形
题目链接:https://vjudge.net/problem/POJ-1015
好题。首先这个状态设计的就比较巧妙:设f[i][j][k]表示前i人选j个,控方-辩方的差值为k,能得到的最大和。这儿把控方和辩方的差值作为状态的一维(可以理解成背包问题的“体积”)。
那么就有转移方程:f[i][j][k] = max(f[i-1][j][k],f[i-1][j-1][k-(p[i]-d[i])]+p[i]+d[i])。然后注意到这个差值可能为负数,所以要把数组下标都加上400,这个在白书习题poj2184里也用到了。最后是打印方案,因为用的是三维的f[i][j][k],所以这儿方案打印就比较方便,详细见代码。应该可以省去第一维的i,但那样记录方案就有点麻(不)烦(会)
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int f[210][30][810],p[210],d[210],ans[30];
int n,m,i,j,k,ansp,ansd,res,dif,cnt,now;
//ansp,ansd分别记录最后p方和d方的和,res记录最大和,dif是最小差值
int main(){
while ((scanf("%d%d",&n,&m))&&n){
for (i=1;i<=n;i++) scanf("%d%d",&p[i],&d[i]);
memset(f,-0x3f,sizeof(f));
for (i=0;i<=n;i++) f[i][0][400]=0; //*初始化,注意偏移量400
for (i=1;i<=n;i++)
for (j=1;j<=m;j++)
for (k=0;k<=800;k++){ //*
if (i-1>=j) f[i][j][k]=f[i-1][j][k];
if (k-p[i]+d[i]>=0&&f[i-1][j-1][k-(p[i]-d[i])]>=0)
f[i][j][k]=max(f[i][j][k],f[i-1][j-1][k-(p[i]-d[i])]+p[i]+d[i]);
}
i=n;j=m; res=0;dif=1e5; cnt=0;
//找到最优解对应的最终状态
for (int l=0;l<=800;l++)
if (f[n][m][l]>=0)
if (abs(l-400)<dif||(abs(l-400)==dif&&res<f[n][m][l])){
k=l; dif=abs(l-400); res=f[n][m][l];
}
//求出一个方案
ansp=ansd=0;
while (j>0){
if (f[i][j][k]==f[i-1][j][k]) i--;
else{
ansp+=p[i]; ansd+=d[i]; ans[++cnt]=i;
k-=(p[i]-d[i]); i--;j--; //*
}
}
printf("Jury #%d\n",++now);
printf("Best jury has value %d for prosecution and value %d for defence:\n",ansp,ansd);
for (i=cnt;i>=2;i--) printf("%d ",ans[i]);
printf("%d\n\n",ans[1]);
}
return 0;
}

浙公网安备 33010602011771号