问题描述
Marsha and Bill own a collection of marbles. They want to split the collection among themselves so that both receive an equal share of the marbles. This would be easy if all the marbles had the same value, because then they could just split the collection in half. But unfortunately, some of the marbles are larger, or more beautiful than others. So, Marsha and Bill start by assigning a value, a natural number between one and six, to each marble. Now they want to divide the marbles so that each of them gets the same total value. Unfortunately, they realize that it might be impossible to divide the marbles in this way (even if the total value of all marbles is even). For example, if there are one marble of value 1, one of value 3 and two of value 4, then they cannot be split into sets of equal value. So, they ask you to write a program that checks whether there is a fair partition of the marbles.
输入格式
Each line in the input file describes one collection of marbles to be divided. The lines contain six non-negative integers n1 , . . . , n6 , where ni is the number of marbles of value i. So, the example from above would be described by the input-line "1 0 1 2 0 0". The maximum total number of marbles will be 20000.
The last line of the input file will be "0 0 0 0 0 0"; do not process this line.
输出格式
For each collection, output "Collection #k:", where k is the number of the test case, and then either "Can be divided." or "Can't be divided.".
Output a blank line after each test case.
样例输入输出
样例输入
1 0 1 2 0 0
1 0 0 0 1 1
0 0 0 0 0 0
样例输出
Collection #1:
Can't be divided.
Collection #2:
Can be divided.
题意概括
给定六种硬币,第i种硬币的价值为i,输入每种硬币的数量ni,判断这些硬币能否分成价值相同的两组。
解析
首先,如果硬币的价值(sum)总数不是2的倍数,那么无论如何都无法分成价值相同的两组,直接输入即可。否则,每组的价值总数就是(sum/2)。那么问题就转化为已知硬币的数量和价值,从中选出一些硬币,问能否使这些硬币的价值综合为(sum/2)(如果一组为(sum/2),那么另一组也肯定为(sum/2))。这显然就可以用多重背包的方法来实现了。将这个背包的容积设为(sum/2),每个硬币的价值和体积都为自己的价值,最后只需要判断总体积为(sum/2)时总价值是否也为(sum/2)即可。
另外,因为数量特别庞大,这里的多重背包需要使用二进制优化。
代码
#include <iostream>
#include <cstdio>
#include <cstring>
#define N 1000000
#define M 1000000
using namespace std;
int n,w,i,j,c[N],v[N],num[N],nc[N],nv[N],ncnt,sum,f[M],cnt;
int main()
{
for(i=1;i<=6;i++) c[i]=i;
while(1){
cnt++;
sum=ncnt=0;
memset(f,0,sizeof(f));
for(i=1;i<=6;i++){
cin>>num[i];
sum+=num[i]*i;
}
if(sum==0) break;
cout<<"Collection #"<<cnt<<":"<<endl;
if(sum%2==1){
cout<<"Can't be divided."<<endl<<endl;
continue;
}
else w=sum/2;
for(i=1;i<=6;i++){
int k;
for(k=1;num[i]-(1<<k)+1>0;k++){
ncnt++;
nc[ncnt]=(1<<(k-1))*c[i];
}
ncnt++;
k--;
nc[ncnt]=(num[i]-(1<<k)+1)*c[i];
}
for(i=1;i<=ncnt;i++){
for(j=w;j>=nc[i];j--){
f[j]=max(f[j],f[j-nc[i]]+nc[i]);
}
}
if(f[w]!=w) cout<<"Can't be divided."<<endl;
else cout<<"Can be divided."<<endl;
cout<<endl;
}
return 0;
}