题意就是有值为1-6的弹子球,给出它们的个数,问能否根据它们的价值平分弹子球。 一个剪枝就是在它们总值为奇数时就可以判定不能平分,若总值为偶数,则取总值的一半为背包最大容量按多重背包处理。 若最终刚好能够取到总值的一半,则可以平分。 #include <iostream> using namespace std; int num,V; //num物品个数,V为最大容量 int f[20005*6]; int c[15],w[15];//c[]物品重量,w[]物品价值 bool flag; //以下为背包模板,参考《背包九讲》 void zero_one_pack(int cost,int weight) { for(int v=V;v>=cost;--v) { if(flag) return; f[v]=max( f[v],f[v-cost]+weight ); if(f[v]==V) flag=true; } } void CompletePack(int cost,int weight) { for(int v=cost;v<=V;++v) { if(flag) return; f[v]=max( f[v],f[v-cost]+weight ); if(f[v]==V) flag=true; } } // 多重背包 void MultipPack(int cost,int weight,int amount) { if (cost*amount>=V) { CompletePack(cost,weight); return ; } int k=1 ; while(k<amount) { if(flag) return ; zero_one_pack(k*cost,k*weight); amount=amount-k; k=k*2; } zero_one_pack(amount*cost,amount*weight); } int main() { int cas=1,t; for(int i=1;i<=6;++i) w[i]=i; while(cin>>c[1]>>c[2]>>c[3]>>c[4]>>c[5]>>c[6]) { if(!c[1]&&!c[2]&&!c[3]&&!c[4]&&!c[5]&&!c[6]) break; V=0; flag=false; memset(f,0,sizeof(f)); for(int i=1;i<=6;++i) V=V+c[i]*i; //计算弹子的总值 t=V; V/=2; //算出总值的一半,按多重背包进行处理,若最多能够取到V则能够平分 for(int i=1;i<=6;++i) { if(t%2!=0) break; //若弹子总值为奇数,则永远不能平分 MultipPack(w[i],w[i],c[i]); } cout<<"Collection #"<<cas++<<":"<<endl; if(flag) cout<<"Can be divided."<<endl<<endl; else cout<<"Can't be divided."<<endl<<endl; } return 0; }