程帅霞

不断受挫,不停起身,不断追寻,不止AC~~

导航

小木棍

小木棍

题目描述

原题来自:题目链接

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

 

输入格式

第一行为一个单独的整数 N 表示砍过以后的小木棍的总数。 第二行为 N 个用空格隔开的正整数,表示 N 根小木棍的长度。

 

输出格式

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

 

样例输入

 

9

5 2 1 5 2 1 5 2 1

 

样例输出

 

6

 

数据范围与提示

 

1<=N<=60

 1 #include<string.h>
 2 #include<stdio.h>
 3 #include<algorithm>
 4 using namespace std;
 5 int n,mid,sum,res,ans;
 6 int a[70],vis[70];//vis[]起标记作用,即标记哪些小木棍被用过
 7 bool cmp(int x,int y)
 8 {
 9     return x>y;
10 }
11 //len表示每一根原始木棍被砍过之后剩余的长度
12 //sta表示每一根原始长度的木棍被砍过一段之后需要从被砍过小木棍(排过序的已经)的下一个开始继续寻找
13 //now表示我们需要的几根原始小木棍
14 int dfs(int len,int sta,int now)
15 {
16     int i,j;
17     if (now==res)//当我们搜到的(now)原始小木棍的根数与我们本来就需要的原始小木棍的根数相等(res)
18         //此时len肯定为0,因为我们now加1的条件就是len为0
19         //即该if语句的真正内在语句是if(now==res&&len==0)
20         return 1;
21 //当len==0的时候就是当前这根原始木棍已经被砍完,我们需要一根新的原始木棍,长度为(ans),即根数加1
22     if (len==0)
23         if (dfs(ans,1,now+1))//只有当len==0的时候now才会加1,我们还是从a[1]开始找,不用担心会重复,因为我们已经做了标记
24             return 1;
25     for (i=sta; i<=n; i++)
26     {
27         //当前这根小木棍没有被用过,并且该木棍的长度小于当前原始木棍剩余的长度
28         if (!vis[i]&&a[i]<=len)
29         {
30             vis[i]=1;//当前这根小木棍已经用过就标记成1
31             if (dfs(len-a[i],i+1,now))//1.1
32                 return 1;
33             //    printf("%d***\n",len-a[i]);
34             //    printf("%d**\n",len);
35             //在返回的时候标记要回溯,即取消标记
36             //【该题代码的重中之重】【搞懂剪枝就成功了】【剪枝也挺难的@-@】
37             vis[i]=0;
38             //剪枝1
39 //对于len==ans这条剪枝,可以用一组数据来说明
40 //例:4 4 3 3 3 3 第一次原始长度为4,前两个4都可以,当到第一个3的时候len-3=1,往后所有小木棍长度都大于1
41 //即1.1那if语句中的函数返回值为0,会从1.1语句往下进行,vis[i](i==3)=0,len=4
42 //本次的原始小木棍的长度ans也为4,即当len==ans的时候就可以直接break
43 //即长度(len)为4的原始小木棍不符合题意,我们要把len++开始探索5(在main()函数中进行)
44             //    printf("%d***%d***%d***%d***\n",len,a[i],i,ans); 1.2
45 //对于函数的返回,如果你不知道返回的len、i、a[i]为多少的时候,你可以直接输出该值,例如1.2
46             if (len==ans/*||len==a[i]*/)
47                 break;
48             //剪枝2
49 //用当前长度的木棍搜下去得不到结果时,用一根同样长度的还是得不到结果,所以可以提前返回
50 //while循环要放在最后,因为我们需要木棍搜下去得不到结果,才进行相同长度木棍加加
51             while(a[i]==a[i+1])
52                 i++;
53             //【都懂了吗@-@】
54         }
55     }
56     return 0;
57 }
58 int main()
59 {
60     int i,j;
61     scanf("%d",&n);
62     for (i=1; i<=n; i++)
63     {
64         scanf("%d",&a[i]);
65         sum+=a[i];
66     }
67 //一根长木棍肯定比几根短木棍拼成同样程度的用处小,即短小的可以更灵活组合
68 //所以按照从大到小进行排序
69     sort(a+1,a+1+n,cmp);
70     for (i=a[1]; i<=sum; i++) //迭代搜索一步一步逼近最优解
71     {
72         if(sum%i!=0)
73             continue;
74         res=sum/i;//res代表的是当原始小木棍的长度为i时,我们需要的多少根原始小木棍
75         ans=i;//ans就是当前我们找到的原始小木棍的长度
76         if(dfs(ans,1,0))//初始判断的小木棍只有0根,我们的a数组下标从1开始,所以我们要从1开始找
77         {
78             printf("%d\n",ans);//因为我们是从最小的原始木棍开始找的,所以当我们找到后就直接输出
79             return 0;
80         }
81     }
82     return 0;
83 }

 

posted on 2021-02-07 15:02  程帅霞  阅读(137)  评论(0编辑  收藏  举报