现有面值为1、2、3、4、5、6的硬币若干枚,现在需要知道能不能将这些硬币分成等额的两堆。
每行输入6个正整数,分别表是面值为1、2、3、4、5、6的硬币的个数,若输入6个0代表输入结束。单种硬币的数量不会超过20000。
若能分割,输出
Can be divided.'',若不能输出
Can’t be divided.’’
首先将每种金额的硬币都分成数堆:
比如一元硬币有n个,那么用一个循环,把他分成1个一堆,2个一堆,4个一堆…2k个一堆.
最后剩下一些不能按照以上规则堆成一堆.把剩下的也堆成一堆.
这时,凡是这些硬币能够组成的金额,都能够由以上产生的几堆硬币组成.
然后就可以转换成比较简单的背包问题.
我们算出所有金币的总金额sum.
如果sum是单数,那么不能划分.
如果这几堆硬币能够组成sum/2,那么就可以划分
如果不能.则不能划分.
#include
long c1, c2, c3, c4, c5, c6, sum, t = 1;
long coin[100], cn, answer[210000];
int part(int a, int b){
int i = 1;
while(a >= i){
coin[cn++] = i * b;
a -= i;
i *= 2;
}
if(a){
coin[cn++] = a * b;
}
}
int dp(){
long i, j;
answer[0] = 1;
for(i = 1; i <= sum; i++){
answer[i] = 0;
}
for(i = 0; i < cn; i++){
for(j = sum; j >= coin[i]; j--){
if(answer[j - coin[i]]){
answer[j] = 1;
}
if(answer[sum]){
printf("Collection #%d:\n", t++);
printf("Can be divided.\n\n");
return 0;
}
}
}
printf("Collection #%d:\n", t++);
printf("Can't be divided.\n\n");
}
int main(){
scanf("%ld%ld%ld%ld%ld%ld", &c1, &c2, &c3, &c4, &c5, &c6);
while(c1 != 0 || c2 != 0 || c3 != 0 || c4 != 0 || c5 != 0 || c6 != 0){
sum = c1*1 + c2*2 +c3*3 +c4*4 + c5*5 + c6*6;
if(sum % 2){
printf("Collection #%d:\n", t++);
printf("Can't be divided.\n\n");
scanf("%ld%ld%ld%ld%ld%ld", &c1, &c2, &c3, &c4, &c5, &c6);
continue;
}
sum /= 2;
cn = 0;
part(c1, 1);
part(c2, 2);
part(c3, 3);
part(c4, 4);
part(c5, 5);
part(c6, 6);
dp();
scanf("%ld%ld%ld%ld%ld%ld", &c1, &c2, &c3, &c4, &c5, &c6);
}
}