poj1011

题意不说了,有中文。
搜索。高难度剪枝。
其实这道题在POJ上的数据太渣。水水的剪枝就可以过。但是UVA的那道一样的题目不行。。推荐一个好的题解
这道题目一开始我只想到3个剪枝方法。然后百度到了另外3个。

  • 首先确定答案的范围,答案必然满足maxlen<=answer<=totlen/2 或者 answer==totlen
  • 然后answer一定是totlen的约数即必须有 totlen%answer==0
  • 其次给长度从大到小排序,这样可以避免无意义的搜索
  • 同一长度的木棒具有同样的效果,即如果第一根该长度的木棒无法满足要求,则跳过所有该长度的木棒(因为结果都一样)
  • 作为当前possibleanswer的开头第一个木棒必然是当前可用木棒集合中最长的,如果最长的都无法满足要求,则当前possibleanswer一定impossible。
  • 如果当前碎木棒正好使得正在拼的木棒满足当前的possibleanswer,但是在它之后的其他木棒无法完成该possibleanswer,则正在拼的这根木棒一定无法满足该possibleanswer。

    贴代码吧:

#include <cstdio>
#include <algorithm>
#define max(a,b) ((a)>(b)?(a):(b))

using namespace std;

int  totnum, requirenum, singlelen, totlen, sticklen[64];
bool check(int curlen, int position, int finishnum);
int  cmp(int a, int b) { return a>b; }

int main(int argc, char const *argv[])
{
    while(scanf("%d", &totnum) != EOF && totnum != 0){
        totlen = 0;
        for(int i = 0; i < totnum; ++i){
            scanf("%d", sticklen+i);
            totlen += sticklen[i];
        }
        sort(sticklen, sticklen+totnum, cmp);
        for(singlelen = sticklen[0]; singlelen <= totlen/2; ++singlelen){
            if(totlen%singlelen==0) {
                requirenum = totlen/singlelen;
                if(check(0, 0, 0)) { break; }
            }
        }
        if(singlelen>totlen/2){ printf("%d\n", totlen);}
        else {printf("%d\n", singlelen);}
    }
    return 0;
}

bool check(int curlen, int position, int finishnum)
{
    static bool flag[64] = {false};
    bool ans = false;
    if(curlen == singlelen){
        if(++finishnum == requirenum) {
            ans = true;
        } else {
            for(position=0;flag[position];++position);
            flag[position] = true;
            ans = check(sticklen[position], position+1, finishnum);
            flag[position] = false;
        }
    } else if(curlen < singlelen) {
        int prelen = 0, newlen;
        for(int pos = position; pos<totnum; ++pos){
            if(flag[pos] || sticklen[pos] == prelen) { continue; }
            prelen = sticklen[pos];
            newlen = curlen+prelen;
            flag[pos] = true;
            ans = check(newlen,pos+1,finishnum);
            flag[pos] = false;
            if(ans || newlen==singlelen || curlen == 0) { break; }
        }
    }
    return ans;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值