题目描述:有一堆石头,每块石头都有一个value,value只有六个数字0-6,现给出每个value的石头的个数,问,这堆是有能否分成value和相等的里两堆。
输入格式:每行一组数据,每行六个整数n1,···,n6,分别表示value为i(i=1···6)的石头的个数。以0 0 0 0 0 0结束输入(该组数据不输出结果)
输出格式:每组数据都要输出一行”Collection #k:”,k是数据的编号,然后输出一行”Can be divided.”或者”Can’t be divided.”
然后每组数据都要输出一个空行!
数据约定:每种value的石头的个数不超过20000.
我的解题过程:这道题目我还是想了蛮久的,发现只有搜索可行。然后,我可耻的TLE了,当然,我并没有submit。。我用的discuss里面的童鞋提供的一组十分强大的数据。。然后我可耻的不知道怎么剪枝了,然后可耻的看了讨论,看了别人的剪枝,此剪枝号称最强的剪枝,但是似乎并不是。。因为上面的数据还是可耻的TLE了。。然后在这个讨论的子讨论里我发现了一个更神奇的剪枝,然后我神奇的AC了。。。
我的分析:对于一种value的石头,如果它的数量达到了能够用一定数量的一种石头让价值和达到60,那么完全可以忽略这些个石头。思考:为什么是60这个数字? 因为。。。1~6的最小公倍数是60.因此,如果value为1的石头,那么它的数量里超出60的部分就完全可以不用考虑。。因此 num[value1] %= 60; 因此。。这个剪枝。。墙大了。num[value(i)] %=(60/i);这样。。数量一下子就减小了。。搜索完全无压力。
#include <cstdio>
bool search(int curval, int target, int* num);
int main(int argc, char const *argv[])
{
int num[6]={0}, cnt=0;
while(scanf("%d%d%d%d%d%d",num,num+1,num+2,num+3,num+4,num+5) != EOF){
if(!num[0] && !num[1] && !num[2] && !num[3] && !num[4] && !num[5]) { break; }
printf("Collection #%d:\n", ++cnt);
for(int i=1; i<7; ++i){ num[i-1] %= (60/i); }
int sumval = num[0]*1+num[1]*2+num[2]*3+num[3]*4+num[4]*5+num[5]*6;
if(sumval&1){ printf("Can't be divided.\n\n"); }
else if(search(0, sumval>>1, num)){ printf("Can be divided.\n\n"); }
else { printf("Can't be divided.\n\n"); }
}
return 0;
}
bool search(int curval, int target, int* num){
bool ret = false;
if(curval==target) { ret=true; }
else if(curval<target){
for(int i=5; i>=0; --i){
if(num[i]==0){ continue; }
if(i+1>target) { continue; }
num[i]--;
if(search(curval+i+1, target, num)) { ret=true; }
num[i]++;
if(ret) { break; }
}
}
return ret;
}