zoukankan      html  css  js  c++  java
  • poj 1011 :Sticks (dfs+剪枝)

    题意:给出n根小棒的长度stick[i],已知这n根小棒原本由若干根长度相同的长木棒(原棒)分解而来。求出原棒的最小可能长度。

    思路:dfs+剪枝。蛮经典的题目,重点在于dfs剪枝的设计。先说先具体的实现:求出总长度sum和小棒最长的长度max,则原棒可能的长度必在max~sum之间,然后从小到大枚举max~sum之间能被sum整除的长度len,用dfs求出所有的小棒能否拼凑成这个长度,如果可以,第一个len就是答案。

    下面就是关键的了,就是这道题dfs的实现和剪枝的设计:

          1.以一个小棒为开头,用dfs看看能否把这个小棒拼凑成len长,如果可以,用vis[i]记录下用过的小棒,然后继续以另外一个小棒为开头,以此类推。

          2.小棒的长度从大到小排序,这个就不解释了。

          3.如果当前最长的小棒不能拼成len长,那么就返回前一步,更改前一步的最长小棒的组合情况(这里不能是全部退出),不用再继续搜索下去了。

          4.最重要的,就是比如说17,9,9,9,9,8,8,5,2……如果当前最长小棒为17,它与第一个9组合之后dfs发现不能拼成len,那么17就不用和后面所有的9组合了,而直接和8开始组合。这个剪枝直接从TLE到16MS,很强大。

    源代码:(160K 16MS)

    #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 ", len);
        }
        return 0;
    }

  • 相关阅读:
    Python高级数据处理与可视化(四)---- 数据存储
    Python高级数据处理与可视化(三)---- Matplotlib图像属性控制 & Pandas作图
    Notepad++
    HDU2819 Swap(二分匹配+输出结果)
    HDU1281 棋盘游戏(二分匹配+找必要的点)
    HDU1083 Courses(二分匹配)
    HDU2444 二分图判断+最大匹配
    HDU1045 Fire Net(二分匹配)
    exam1802 Bounty Hunter II(DAG的最小路径覆盖)
    SDUSTOJ 1801 LIS2(最长上升子序列不同值的数量)
  • 原文地址:https://www.cnblogs.com/heiming/p/5893171.html
Copyright © 2011-2022 走看看