POJ1011 木棒 【题目详解】

 

题意:乔治拿来一组等长的木棒,将它们随机地砍断,使得每一节木棍的长度都不超过50个长度单位。然后他又想把这些木棍恢复到为裁截前的状态,但忘记了初始时有多少木棒以及木棒的初始长度。请你设计一个程序,帮助乔治计算木棒的可能最小长度。每一节木棍的长度都用大于零的整数表示。
   
    看题目明显知道这是一道简单搜索,只不过需要几项剪枝,初步思路肯定是从小到大枚举或二分长度(其实二分没什么卵用),然后把每一个枚举到的长度与全部小木棍比对,看看这个能不能做恢复前的原长即可;
    然后的问题就是,枚举有没有技巧?
    当然有了。。。。。。
    对于现有木棒来说,能用长的塞绝对不用短的,这就好比我在用东西装箱子,如果大的能装下,绝对不用小的去装,因为我如果一上来马上就把小的都固定了,万一以后需要用小的来填补缝隙和空子,就会造成不必要的浪费或者压根装不满;所以这个道理就是小木棒比大木棒适应性更好,这样的应该留到最后;所以现有木棒应该被排序一遍,然后从大到小枚举能否覆盖枚举到的答案长度;
    在枚举答案长度的时候,应该从当前最长的那根现有木棍的长度开始枚举。因为原有木棒不可能比切完之后还短;
最长呢?也不能超过总长度;
    然后值得一提的就是剪枝方法,可以有以下几种:
    1.我在枚举的时候,要看这个结果能否出答案(可行性剪枝),如果总长除以我枚举到的长度根本除不开,那我也没必要去搜索了;
    2.我已经占用的木条在接下来的递归中直接不予循环;
    4.如果我的木棒为5 3 3 3 3 2 2 1......,那么我搜过第一个3之后如果不可行的话,后面的3就可以直接跳过嘛,这一剪枝能剪死非常非常高的复杂度;
    好了这道题仅此而已,下面上代码;
 
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<string>
 5 #include<cstring>
 6 #include<cstdlib>
 7 #include<algorithm>
 8 using namespace std;
 9 const int MAXN=65;
10 int n,m,k;
11 int lenth;
12 bool flag=0,vis[MAXN];
13 int stick[MAXN];
14 bool cmp(int a,int b){
15     return a>b;
16 }
17 void dfs(int dep,int nl,int w)
18 {
19     if(flag) return ;
20     if(nl==0){
21         k=0;
22         while(vis[k])k++;
23         vis[k]=true;
24         dfs(dep+1,stick[k],k+1);
25         vis[k]=false;
26         return ;
27     }
28     if(nl==lenth){
29         if(dep==n) flag=true;
30         else{
31             dfs(dep,0,0);
32         }
33         return ;
34     }
35     for(int i=w;i<n;i++){
36         if(!vis[i]&&nl+stick[i]<=lenth){
37             if(!vis[i-1]&&stick[i]==stick[i-1])continue;
38             vis[i]=true;
39             dfs(dep+1,nl+stick[i],i+1);
40             vis[i]=false;
41         }
42     }
43 }
44 int main()
45 {
46     while(scanf("%d",&n)&&n){
47         int tot=0;
48         flag=false;
49         for(int i=0;i<n;i++){
50             scanf("%d",&stick[i]);
51             tot+=stick[i];
52         }
53         sort(stick, stick+n, cmp);
54         for(lenth = stick[0];lenth < tot; lenth++){
55             if(tot%lenth==0){
56                 memset(vis , 0 , sizeof(vis));
57                 dfs(0,0,0);
58                 if(flag)break;
59             }
60         }
61         printf("%d",lenth);
62         puts("");
63     }
64     return 0;
65 }
View Code

 

posted @ 2018-04-05 09:56  杜宇一声  阅读(1696)  评论(0编辑  收藏  举报