• 洛谷P1120 小木棍


    洛谷1120 小木棍

    题目描述

        乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过50。
        现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它们的长度。
        给出每段小木棍的长度,编程帮他找出原始木棍的最小可能长度。

    输入输出格式

    输入格式:

    输入文件共有二行。
    第一行为一个单独的整数N表示砍过以后的小木棍的总数,其中N≤60
    (管理员注:要把超过50的长度自觉过滤掉,坑了很多人了!)
    第二行为N个用空个隔开的正整数,表示N根小木棍的长度。

    输出格式:

    输出文件仅一行,表示要求的原始木棍的最小可能长度

    输入输出样例

    输入样例#1:

    9

    5 2 1 5 2 1 5 2 1

    输出样例#1:

    6

    【思路】

      枚举+回溯法构造判定。

      不难想到从小到大枚举原木棍的长度,但是长度最大可以为300,太大了,我们换而从小到大枚举原木棍根数num,只要可以构造出num根相同长度len的木棍则完成任务。

      如何判定能够构造成功?回溯法。

      先对数据由大到小sort,这样在搜索的时候会先尝试长度大的木棍,显然先选大长度的木棍是优于选小长度的,因为小长度会更有用(可以组合的更多)。

      以目前组装的第几根木棍d、目前组装的长度nowlen以及该从哪开始枚举木棍的下标nowi为状态,搜索是否能够使d==num+1即可。

      剪枝:

    1、   木棍数目枚举范围:最大为 长度和/最大长度

    2、   木棍数目是否符合要求:木棍数目为总长度的约数。

    3、   后缀和判断解不可行。

    4、   Nowi的使用减少同一根小棒的枚举

    5、   每次组装新的木棍的时候人为选择最长的木棍(加速枚举中nowlen+a[i]<len的判断,否则会多拓展一层)

    【代码】

     1 #include<iostream>
     2 #include<algorithm>
     3 using namespace std;
     4 
     5 const int maxn = 60+10;
     6 
     7 int a[maxn],cnt[maxn];
     8 int len,num,n;
     9 int suff_s[maxn];
    10 
    11 inline bool cmp(const int& a,const int& b) {
    12     return a>b;
    13 }
    14 bool dfs(int d,int nowlen,int nowi) {
    15     if(d==num) return true;
    16     
    17     if(len-nowlen > suff_s[nowi]) return false; 
    18     
    19     for(int i=nowi;i<n;i++) if(cnt[a[i]]) {
    20        if(a[i]+nowlen < len) {
    21                 cnt[a[i]]--;
    22                 if(dfs(d,nowlen+a[i],i+1)) return true;
    23                 cnt[a[i]]++;
    24        }
    25        if(a[i]+nowlen==len) {
    26                   cnt[a[i]]--;
    27                   int j;
    28                for(j=0;j<n;j++) if(cnt[a[j]]&&a[j]<len) break;
    29                cnt[a[j]]--;
    30                if(dfs(d+1,a[j],j+1)) return true;
    31                cnt[a[j]]++;
    32                cnt[a[i]]++;
    33         }
    34     }
    35     return false;
    36 }
    37 int main() {
    38     ios::sync_with_stdio(false);
    39     cin>>n;
    40     int tot=0,x,_max=0,maxx=0;
    41     for(int i=0;i<n;i++) {
    42         cin>>x;
    43         if(x<=50) {
    44            a[tot++]=x;
    45            suff_s[tot-1]=x;
    46            _max+=x;
    47            maxx=max(maxx,a[tot-1]);
    48            cnt[x]++;
    49         }
    50     }
    51     n=tot;
    52     for(int i=n-2;i>=0;i--) suff_s[i] += suff_s[i+1];
    53     sort(a,a+n,cmp);
    54     int t=_max/maxx; if(t>n) t=n;
    55     cnt[a[0]]--;
    56     for(num=t;num>=0;num--) if(_max%num==0) {
    57         len=_max/num;
    58         if(dfs(0,a[0],1)) {
    59             cout<<len;
    60             break;
    61         }
    62     }
    63     return 0;
    64 } 
  • 相关阅读:
    深入c#的String类
    C#语法快速热身
    【BZOJ】1676: [Usaco2005 Feb]Feed Accounting 饲料计算
    【BZOJ】2056: gift? 高精度?
    【BZOJ】3036: 绿豆蛙的归宿
    【BZOJ】2321: [BeiJing2011集训]星器
    【VIJOS】P1401复制CS
    【BZOJ】2453: 维护队列&&【BZOJ】2120: 数颜色 二分+分块 双倍经验
    【BZOJ】3343: 教主的魔法
    【BZOJ】1452: [JSOI2009]Count 树状数组
  • 原文地址:https://www.cnblogs.com/lidaxin/p/4861544.html
Copyright © 2020-2023  润新知