/* 多重背包问题 该题求的是能否拿到总价值的一半 可以假设 每个球消耗的空间和它的价值相等 则本题可转化为:在总空间一半的口袋里能否得到总价值的一半(因为价值密度为1,故最多能达到一半) */ #include<stdio.h> #include<string.h> int d[120000],n[7],w; void cpack(int c,int ww) { int j; for(j=c;j<=w;j++) { if((d[j-c]+ww)>d[j]) d[j]=d[j-c]+ww; } } void znpack(int c,int ww) { int j; for(j=w;j>=c;j--) { if(d[j]<(d[j-c]+ww)) d[j]=d[j-c]+ww; } } void mpack(int c,int ww,int nn) { if(c*nn>=w) { cpack(c,ww); return; } int k=1; while(k<nn) { znpack(k*c,k*ww); nn=nn-k; k=k*2; } znpack(nn*c,nn*ww); } int main() { int q=1,i; while(1) { w=0; for(i=1;i<=6;i++) { scanf("%d",&n[i]); w+=i*n[i]; } if(!w) break; if(w%2) { printf("Collection #%d:\nCan't be divided.\n\n",q++); continue; } w=w/2; d[0]=0; memset(d,0,sizeof(d)); for(i=1;i<=6;i++) { if(!n[i]) continue; mpack(i,i,n[i]); } if(d[w]!=w) printf("Collection #%d:\nCan't be divided.\n\n",q++); else printf("Collection #%d:\nCan be divided.\n\n",q++); } return 0; }
以上是我仿别人的,我原先自己写的因为数组开小了,系统给了个Runtime Error(ACCESS_VIOLATION),同时没有把球消耗的空间假设为同它的价值,所以只能求:占用总数一半的价值,最多(或最少,最少可以将数组初始化为正无穷,不用判断数据是否合法)能拿到几个球;若d[一般价值]=初始化,则不可以平分。因此,处理比较复杂。
#include<stdio.h> int d[120000],n[7],w; void cpack(int c,int ww) { int j; for(j=c;j<=w;j++) { if((d[j-c]+ww)<d[j]) d[j]=d[j-c]+ww; } } void znpack(int c,int ww) { int j; for(j=w;j>=c;j--) { if(d[j]>(d[j-c]+ww)) d[j]=d[j-c]+ww; } } void mpack(int c,int ww,int nn) { if(c*nn>=w) { cpack(c,ww); return; } int k=1; while(k<nn) { znpack(k*c,k*ww); nn=nn-k; k=k*2; } znpack(nn*c,nn*ww); } int main() { int q=1,i; while(1) { w=0; for(i=1;i<=6;i++) { scanf("%d",&n[i]); w+=i*n[i]; } if(!w) break; if(w%2) { printf("Collection #%d:\nCan't be divided.\n\n",q++); continue; } w=w/2; d[0]=0; for(i=1;i<=w;i++) d[i]=999999999; for(i=1;i<=6;i++) mpack(i,1,n[i]); if(d[w]==999999999) printf("Collection #%d:\nCan't be divided.\n\n",q++); else printf("Collection #%d:\nCan be divided.\n\n",q++); } return 0; }