洛谷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 } 
原文地址:https://www.cnblogs.com/lidaxin/p/4861544.html