poj1015 Jury Compromise[背包]
每一件物品有两个属性。朴素思想是把这两种属性都设计到状态里,但空间爆炸。又因为这两个属性相互间存在制约关系(差的绝对值最小),不妨把答案设计入状态中,设$f[i][j]$选$i$个人,两者之差$j$。这样dp。于是$O(NM^3)$暴力背包即可,记录转移,也就是$g[i][j][k]$来表示当前到这个人$i$的时候选了$j$人,是怎么转移的,如果由$j-1$转移,说明这个人$i$选了。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<algorithm> 6 #include<queue> 7 #define dbg(x) cerr<<#x<<" = "<<x<<endl 8 #define _dbg(x,y) cerr<<#x<<" = "<<x<<" "<<#y<<" = "<<y<<endl 9 using namespace std; 10 typedef long long ll; 11 template<typename T>inline char MIN(T&A,T B){return A>B?A=B,1:0;} 12 template<typename T>inline char MAX(T&A,T B){return A<B?A=B,1:0;} 13 template<typename T>inline T _min(T A,T B){return A<B?A:B;} 14 template<typename T>inline T _max(T A,T B){return A>B?A:B;} 15 template<typename T>inline T read(T&x){ 16 x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1; 17 while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x; 18 } 19 const int N=200+5,M=800+7,INF=0x3f3f3f3f; 20 int f[22][M],g[N][22][M],a[N],b[N],sen[M]; 21 int n,m,ans,thx,orz,T; 22 23 int main(){//freopen("test.in","r",stdin);//freopen("test.out","w",stdout); 24 while(read(n),read(m),n||m){ 25 thx=orz=ans=0; 26 for(register int i=0;i<=m;++i)for(register int j=0;j<=800;++j)f[i][j]=-INF; 27 memset(g,0,sizeof g); 28 for(register int i=1;i<=n;++i)read(a[i]),read(b[i]); 29 f[0][400]=0; 30 for(register int i=1;i<=n;++i) 31 for(register int j=_min(i,m);j;--j) 32 for(register int k=a[i]-b[i];k<=800;++k) 33 if(MAX(f[j][k],f[j-1][k-(a[i]-b[i])]+a[i]+b[i]))g[i][j][k]=j-1; 34 else g[i][j][k]=j; 35 for(register int i=0;i<=400;++i)if(f[m][400+i]>=0||f[m][400-i]>=0){ 36 ans=f[m][400+i]>f[m][400-i]?400+i:400-i;break; 37 } 38 int i=n,j=m; 39 while(i){ 40 if(g[i][j][ans]==j-1)sen[j]=i,thx+=a[i],orz+=b[i],ans-=(a[i]-b[i]),--i,--j; 41 else --i; 42 } 43 printf("Jury #%d\n",++T); 44 printf("Best jury has value %d for prosecution and value %d for defence: \n",thx,orz); 45 for(register int i=1;i<=m;++i)printf(" %d",sen[i]); 46 puts(""); 47 } 48 return 0; 49 }