poj1011——Sticks

来源:互联网 发布:软件测试面试大全 编辑:程序博客网 时间:2024/06/05 17:19

题目大意:取一些长度相同的木棍,将他们切割成随意长度的小木棍,现在要将他们拼回原状,问每根原始木棍的长度最小值

输入:(输入以0结束)

            切割后的木棍个数(最多64个)

            每个棍的长度(中间用空格分隔)

输出:木棍的原长度最小值

分析:dfs+剪枝

           大致思路:最长的小木棍max,和所有小木棍长度的总和sum,那么原木棍长度一定在max~sum之间,从max开始枚举能被sum整除的原木棍长度len,再dfs(枚举从某个小木棍开始,能不能拼凑成len长)求出所有小木棍能否拼凑出这个长度

           各种剪枝:1.所有小木棍按长度从大到小排序(越长的小木棍对后面小木棍的约束就越大,按降序排列可能会在最靠近根的地方剪枝)

                             2.跳过重复长度的小木棍(比如当前木棍与小木棍A组合dfs发现不能凑成len,后面所有跟A长度相同的小木棍就不用再组合了)

                             3.如果当前最长小木棍都不能凑成len,则返回上一步,更改上一步的组合情况

代码:转载自http://blog.sina.com.cn/s/blog_6635898a0100lgq0.html

#include<iostream>
#include<algorithm>
using namespace std;
const int Max = 65;

 

int n, len, stick[Max];
bool flag, vis[Max];

 

bool cmp(int a, int b){
    return a > b;
}

 

void dfs(int dep, int now_len, int u){   // dep为当前已被用过的小棒数,u为当前要处理的小棒。
    if(flag) return;
    if(now_len == 0){                    //  当前长度为0,寻找下一个当前最长小棒。
        int k = 0;
        while(vis[k]) k ++;              //  寻找第一个当前最长小棒。
        vis[k] = true;
        dfs(dep + 1, stick[k], k + 1);
        vis[k] = false;
        return;
    }
    if(now_len == len){                  //  当前长度为len,即又拼凑成了一根原棒。
        if(dep == n) flag = true;        //  完成的标志:所有的n根小棒都有拼到了。
        else dfs(dep, 0, 0);
        return;
    }
    for(int i = u; i < n; i ++)
        if(!vis[i] && now_len + stick[i] <= len){
            if(!vis[i-1] && stick[i] == stick[i-1]) continue;      //  不重复搜索:最重要的剪枝。
            vis[i] = true;
            dfs(dep + 1, now_len + stick[i], i + 1);
            vis[i] = false;
        }
}

 

int main(){
    while(scanf("%d", &n) && n != 0){
        int sum = 0;
        flag = false;
        for(int i = 0; i < n; i ++){
            scanf("%d", &stick[i]);
            sum += stick[i];
        }
        sort(stick, stick + n, cmp);     //  从大到小排序。
        for(len = stick[0]; len < sum; len ++)
            if(sum % len == 0){          //  枚举能被sum整除的长度。
                memset(vis, 0, sizeof(vis));
                dfs(0, 0, 0);
                if(flag) break;
            }
        printf("%d\n", len);
    }
    return 0;
}


原创粉丝点击