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
",++now);
	  printf("Best jury has value %d for prosecution and value %d for defence:
",ansp,ansd);
	  for (i=cnt;i>=2;i--) printf("%d ",ans[i]);
	  printf("%d

",ans[1]);
	}
	return 0;
}

  

原文地址:https://www.cnblogs.com/edmunds/p/13560018.html