poj1014

题目描述:有一堆石头,每块石头都有一个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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值