poj1011 Sticks DFS深度优先搜索+剪枝

这道题目吧,我看了蛮久的别人的博客,突然发现有一个剪枝,剪完之后从超时变成了0ms,太牛逼了。
我的代码下面都有讲解,自己看看就OK了。
闲话不多说,直接上代码:

#include
#include
#include
#include
#include
#include

using namespace std;

int a[70], n, len;//a是小棒的长度,n是有多少根,len是尝试len是否可以完成 
bool p[70], flag;//p记录是否使用过,flag是是否完成 


bool cmp(int x, int y) {//从大到小排序 
    return x > y;
}

void dfs(int x, int pre, int y) {//x为当前摆了几根,pre为当前的长度,y为接下来
                                //要摆第几根 
    if(flag)
        return;
    if(pre == 0) {//如果当前没有摆任意一跟 
        int l = 0;
        while(p[l])
            ++l;
        p[l] = true;
        dfs(x + 1, a[l], l + 1);
        p[l] = false;
        return;
    }
    if(pre == len) {//已经摆好了长度为Len的 
        if(n == x)//全部摆好 
            flag = true;
        else//只摆好了一部分 
            dfs(x, 0, 0);
        return;
    }
    int i, j;
    for(i = y;i < n; ++i)//一个个尝试 
        if(!p[i] && (pre + a[i] <= len)) {//可以摆放 
            if(!p[i - 1] && a[i] == a[i - 1])//防止重复搜索,最重要的剪枝 
                continue;
            p[i] = true;
            dfs(x + 1, pre + a[i], i + 1);//继续搜索 
            p[i] = false;
        }
}

int main() {
    int i, j;
    while(scanf("%d", &n) && n != 0) {
        int sum = 0;//表示总长度和 
        for(i = 0;i < n; ++i) {
            scanf("%d", &a[i]);
            sum += a[i];
        }
        flag = false;
        sort(a, a + n, cmp);
        for(len = a[0];len < sum; ++len)//长度只可能是这个区间之内 
            if(sum % len == 0) {//可以整除 
                memset(p, 0, sizeof(p));
                dfs(0, 0, 0);
                if(flag)
                    break;
            }
        printf("%d\n", len);//输出 
    }
    return 0;
}

额,就是这么多,大家加油吧

你可能感兴趣的:(dfs,poj)