zoukankan      html  css  js  c++  java
  • 【洛谷UVA307】小木棍Sticks

    小木棍Sticks【传送门】

    算法的话:dfs+超强剪枝;

    (另外注意UVA上好像不接受万能头[因为万能头WA了两次,瑟瑟发抖])

     思路:

    最直接的思路,枚举木棍长度来dfs,但这样很容易就TLE了。

    dfs的四项关键字:

    1.num:剩多少切割后的木棍没有使用;
    2.rest:还需要rest的长度可以凑成一个切割前的木棍;
    3.len:切割前的木棍长度;
    4.last:当前切割后的木棍起始的下标;(对于初始状态dfs last是1还是0好迷啊,好像初始状态是1或者0都可以ac???) 行吧就当我没说亲测不行qwq

    目标条件:num=0且rest=0;

    剪枝1:对于这些木棍来说,无论怎样分,若满足条件,那么木棍长度一定是总和的倍数; 

    剪枝2:搜索上下界:上界:所有木棍的长度和,下界:最长一根木棍的长度;

    剪枝3:将切割后的木棍按从大到小排列,对于一根切割后木棍,如果它不能满足拼成一根长度为len的木棍,那么它之前的比它长的也显然不行,因此last的作用就是减少枚举次数,每次从上一次的last+1枚举就可以了;

    剪枝4:如果一根木棍的长度>rest,那么对于每一根长度与之相同的木棍都不可能组合,直接跳过减少枚举次数;

    剪枝5:如果当前切割后的木棍长度=len,但组装失败(如果成功就已经return true了)即返回false,因为从大到小排序,当前的切割后木棍明明可以组成成功,但后面的切割后的木棍却组成失败,说明后面的切割后的木棍长度不够或者直接构不成(剩下的切割后的任意长度和!=切割前的木棍长度),那么继续搜肯定不行;????

    #include <iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    int n, mg[100], tmp, top = 1, tt = 0, vis[100],T;
    
    int cmp(int a, int b) {
        return a > b;  
    }
    bool dfs(int num , int len , int rest , int last ) {
        if (rest == 0 && num == 0)  
            return 1;  
        if (num == 0)//没有木棍,不能拼成的情况 
            return 0;     
        if (rest == 0) {//如果现在刚好组成一根木棍,更新rest变为枚举的切割前木棍的长度 
            rest = len;   
            last = 0;//last再次更新为0 
        }                                       
        for (int i = last + 1; i < top; i++) {  //剪枝3 
            if (vis[i])
                continue;                                   
            if (mg[i] > rest) {                             
                while (mg[i] == mg[i + 1] && i < top) i++;  //剪枝4 
                continue;
            }
            vis[i] = 1;  
            if (dfs(num - 1, len, rest - mg[i], i))//选择这根木棍后继续递归,判断是否可以构成一根木棍 
                return 1;  
            vis[i] = 0;    
            if ((mg[i] == rest) || (len == rest))//剪枝5:这句话亲测对于提速还是很有效的 
                break;                                 
            while (mg[i] == mg[i + 1] && i < top) i++; 
        }
        return 0;
    }
    int main() {
        while(1){//while循环来输入多组数据 
            memset(mg,0,sizeof(mg));//因为处理多组数据,所以记得清空数组 
            memset(vis,0,sizeof(vis));
            tt = 0;top = 1/*count number*/;
            cin>>n;
            if(n == 0) return 0;
        for (int i = 1; i <= n; i++) {
            cin >> tmp;
            mg[top++] = tmp,/*存到数组里*/ tt += tmp;//求和 
        }
        sort(mg + 1, mg + top, cmp);//从大到小排序 
        for (int i = mg[1]; i <= tt; i++) {//剪枝2 
            if (tt % i != 0)//剪枝1
                continue;                 
            if (dfs(top - 1/*因为最后top会在这n个数的基础上+1,故dfs起点为top-1*/, i, i, 0)) {//if this i is ok to make sticks,just choose it and break;
                cout << i <<endl;
                break;
            }
        }
        }
        
        return 0;
    }

    立下凌云壮flag,咱今天绝对不理yy,咱不烦yy,咱不让yy烦

     

     end-

  • 相关阅读:
    [BZOJ] 2276: [Poi2011]Temperature
    [Codevs] 5037 线段树练习4加强版
    [Codevs] 4919 线段树练习4
    [Codevs] 1082 线段树练习3
    [Codevs] 1080 线段树练习
    [Codevs] 1081 线段树练习 2 ----“分块!”
    1629: [Usaco2007 Demo]Cow Acrobats
    Kruskal || BZOJ 1601: [Usaco2008 Oct]灌水 || Luogu P1550 [USACO08OCT]打井Watering Hole
    SET || BZOJ 1588: [HNOI2002]营业额统计 || Luogu P2234 [HNOI2002]营业额统计
    线段树合并+并查集 || BZOJ 2733: [HNOI2012]永无乡 || Luogu P3224 [HNOI2012]永无乡
  • 原文地址:https://www.cnblogs.com/zhuier-xquan/p/10994567.html
Copyright © 2011-2022 走看看