• POJ 1011 很经典的树枝拼凑的深度搜索


    Sticks
    Time Limit: 1000MS   Memory Limit: 10000K
    Total Submissions: 142684   Accepted: 33684

    Description

    George took sticks of the same length and cut them randomly until all parts became at most 50 units long. Now he wants to return sticks to the original state, but he forgot how many sticks he had originally and how long they were originally. Please help him and design a program which computes the smallest possible original length of those sticks. All lengths expressed in units are integers greater than zero.

    Input

    The input contains blocks of 2 lines. The first line contains the number of sticks parts after cutting, there are at most 64 sticks. The second line contains the lengths of those parts separated by the space. The last line of the file contains zero.

    Output

    The output should contains the smallest possible length of original sticks, one per line.

    Sample Input

    9
    5 2 1 5 2 1 5 2 1
    4
    1 2 3 4
    0
    

    Sample Output

    6
    5
    


    问题:



    乔治拿来一组等长的木棒,将它们随机地裁断,使得每一节木棒的长度都不超过50个长度单位。然后他又想把这些木棒恢复到为裁截前的状态,但忘记了木棒的初始长度。请你设计一个程序,帮助乔治计算木棒的可能最小长度。每一节木棒的长度都用大于零的整数表示
     
    输入:由多个案例组成,每个案例包括两行。第一行是一个不超过64的整数,表示裁截之后共有多少节木棒。第二行是经过裁截后,所得到的各节木棒的长度。在最后一个案例之后,是零。
     
    输出:为每个案例,分别输出木棒的可能最小长度。每个案例占一行。

    思路: 给你n 木棍碎片,要求还原原木棍,且原木棍等长,问最短长度是多少。

    1.先求sum总和,以最长的一根长度开始枚举长度,每次长度加一,枚举+深搜

    2.寻找一个可以sum%len=0的len,必须先对木棒从大到小排序,枚举木棍时,越长对整除拼凑的影响越大,比如数据 4 1,2,3,4  如果是从小开始找,前面可以整除,后面拼凑更不容易达到len,可以联系实际具体想一下

    3.dfs判断搜到的不同情况进行不同处理,注意每次跳出一个dfs都是一次回溯,需要将回溯的前一个节点重新置空。

    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    const int maxn = 70;
    
    
    int sticks[maxn];
    int n,len;
    bool flag,vis[maxn];
    
    
    int cmp(int a, int b) {
        return a>b ;
    }
    
    void dfs(int deep,int now_len,int pos) { //deep为当前已经使用过的小棒数,pos为当前要处理的小棒,now_len为当前拼凑的长度
        if(flag)
            return;
        if(now_len == 0) { //第一次或者从len的第二次新的找起,与34行情况对应,此时下一步的长度搜索对应27行,从下一根长度开始搜索
            int k = 0;
            while(vis[k])
                k++; //已经访问的跳过
            vis[k] = true;
    
            dfs(deep+1,sticks[k],k+1);
            vis[k] = false;
            return;
        }
    
        if(now_len == len) {  //又找到一根,判断是否找完,没找完从长度0继续找,累加
            if(deep ==n) flag = true;
            else dfs(deep,0,0); //如果当前已经找到了一个能整除的长度,但是拼成的根数不是总根数,那么在vis的基础之上,继续搜索
            return;
        }
    
        //已经拼凑到一根或一根以上,但是没有拼凑到len的情况,此时就要枚举没有访问的树枝,开始拼凑
        for(int i = pos; i < n; i++) {
            if(!vis[i] && now_len + sticks[i] <= len) {
                if(!vis[i-1] && sticks[i] == sticks[i-1]) continue; //重要的一步剪枝,让时间从tle到16ms的一步,后台数据有很多重复的,在递归中减少一个分支延展能节约很多时间
                vis[i] = true;
                dfs(deep+1,now_len+sticks[i],i+1);
                vis[i] = false; //每次跳出一个递归后,就是一个回溯,相当于一个树返回上一个节点,所以要重新标记
            }
        }
    }
    
    int main() {
        while(scanf("%d",&n)&&n){
                int sum = 0;
                flag = false;
            for(int i = 0; i < n; i++) {
                scanf("%d",&sticks[i]);
                sum += sticks[i];
            }
            sort(sticks,sticks+n,cmp);
            for(len = sticks[0]; len < sum; len++) {
                if(sum %len == 0) {
                    memset(vis,false,sizeof(vis));
                    dfs(0,0,0);//已处理的树枝数目0,当前长度0,要处理的树枝0
                    if(flag)
                        break;
                }
            }
                printf("%d
    ",len);
    
    
        }
         return 0;
    }
    



  • 相关阅读:
    Java中Comparable与Comparator的区别
    LeetCode[5] 最长的回文子串
    LeetCode[3] Longest Substring Without Repeating Characters
    LeetCode 7. Reverse Integer
    统计单词出现的次数
    System.arraycopy()和Arrays.copyOf()的区别
    SyncToy
    查看端口占用及进程号
    TCP协议
    python 的日志logging模块学习
  • 原文地址:https://www.cnblogs.com/zhangmingzhao/p/7256668.html
Copyright © 2020-2023  润新知