小木棍
小木棍
题目描述
原题来自:题目链接
乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过 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 }