• AcWing:167. 木棒(dfs + 剪枝)


    乔治拿来一组等长的木棒,将它们随机地砍断,使得每一节木棍的长度都不超过50个长度单位。

    然后他又想把这些木棍恢复到为裁截前的状态,但忘记了初始时有多少木棒以及木棒的初始长度。

    请你设计一个程序,帮助乔治计算木棒的可能最小长度。

    每一节木棍的长度都用大于零的整数表示。

    注意: 数据中可能包含长度大于50的木棒,请在处理时忽略这些木棒。

    输入格式

    输入包含多组数据,每组数据包括两行。

    第一行是一个不超过64的整数,表示砍断之后共有多少节木棍。

    第二行是截断以后,所得到的各节木棍的长度。

    在最后一组数据之后,是一个零。

    输出格式

    为每组数据,分别输出原始木棒的可能最小长度,每组数据占一行。

    输入样例:

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

    输出样例:

    6
    5

    算法:dfs + 剪枝

    题解:剪枝:1、优先搜索顺序(从大大小),优先尝试较长的木棒。

          2、要求先后加入的木棒有单调性,因为你每根木棒都要用,之前加入和之后加入都是一个样。

          3、当拼接一个新木棒时,我加入一个木棒,失败了,说明,之后用到这个木棒拼接一个新木棒的时候都会失败。

          4、当我现在我要加入的木棒拼接上去,正好等于拼接的长度,但是拼接失败了,说明之后继续拼接下去也是失败。

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    
    using namespace std;
    
    const int maxn = 1e5+7;
    
    int arr[maxn];
    int vis[maxn];
    int k, cnt;
    
    bool cmp(int a, int b) {
        return a > b;
    }
    
    bool dfs(int stick, int cal, int last, int len) {
        if(stick > cnt) {   //当所有木棒已经拼好时,搜索成功
            return true;
        }
        if(cal == len) {    //木棒已经拼好,去拼下一根
            return dfs(stick + 1, 0, 0, len);
        }
        int fail = 0;   //剪枝2,记录重复值
        for(int i = last; i < k; i++) {
            if(!vis[i] && cal + arr[i] <= len && fail != arr[i]) {
                vis[i] = 1;
                if(dfs(stick, cal + arr[i], i + 1, len)) {
                    return true;
                }
                vis[i] = 0;
                fail = arr[i];
                if(cal == 0 || cal + arr[i] == len) {    //剪枝3,剪枝4
                    return false;
                }
            }
        }
        return false;       //当所有分支都尝试过,并且还没成功
    }
    
    int main() {
        int n;
        while(~scanf("%d", &n) && n) {
            int sum = 0, max_len = 0, x;
            k = 0;
            for(int i = 1; i <= n; i++) {
                scanf("%d", &x);
                if(x > 50) {
                    continue;
                }
                sum += x;
                max_len = max(max_len, x);
                arr[k++] = x;
            }
            sort(arr, arr + k, cmp);    //剪枝1
            int i;
            for(i = max_len; i <= sum; i++) {
                if(sum % i != 0) {
                    continue;
                }
                cnt = sum / i;      //获取木棒的数量
                for(int j = 0; j < k; j++) {
                    vis[j] = 0;
                }
                if(dfs(1, 0, 0, i)) {  
                    break;
                }
            }
            printf("%d
    ", i);
        }
        return 0;
    }
  • 相关阅读:
    【NOIP2016提高组】 Day1 T3 换教室
    【NOIP2016 Day1 T2】天天爱跑步
    web@前端--html,css,javascript简介、第一个页面(常用标签简介)
    MySQL--视图view、触发器trigger、事务(start transaction)、存储过程(特殊的数据逻辑处理函数)、流程控制(if,case....)
    MySQL--pymysql模块
    MySQL--(了解)可能会用到的内置函数
    MySQL--详细查询操作(单表记录查询、多表记录查询(连表查询)、子查询)
    MySQL--表操作(约束条件foreign key关联表 多对1,多对多,1对1)
    MySQL--表操作(innodb表字段数据类型、约束条件)、sql_mode操作
    MySQL基本语句、存储引擎
  • 原文地址:https://www.cnblogs.com/buhuiflydepig/p/11348544.html
Copyright © 2020-2023  润新知