题目
题目描述
乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过5050。
现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它们的长度。
给出每段小木棍的长度,编程帮他找出原始木棍的最小可能长度。
输入输出格式
输入格式:
共二行。
第一行为一个单独的整数N表示砍过以后的小木棍的总数,其中N≤65N≤65
(管理员注:要把超过5050的长度自觉过滤掉,坑了很多人了!)
第二行为NN个用空个隔开的正整数,表示NN根小木棍的长度。
输出格式:
一个数,表示要求的原始木棍的最小可能长度
输入输出样例
说明
2017/08/05
数据时限修改:
-#17 #20 #22 #27 四组数据时限500ms500ms
-#21 #24 #28 #29 #30五组数据时限1000ms1000ms
其他时限改为200ms200ms(请放心食用)
分析
- 很显然,是一道搜索dfs
- 所以我们现在就要考虑如何优化
- 首先,我们需要去除50的
- 进行排序,排序的目的是,到了后面如果加上当前我的最大值还是不够的话就return
- 然后,我们的循环就是肯定从最大的一根木棍到tot/2(因为如果是到tot那么只有可能就是只有一根)
- 因为每段木棍都是整数,所以我们一定是要成tot的倍数
- 最后因为我们是找最小值,出现第一个 个数乘以公约数==tot 直接输出即可
代码
1 #include<iostream> 2 #include<cstdlib> 3 #include<algorithm> 4 using namespace std; 5 int a[10001],cnt,tot,maxx; 6 int used[10001]; 7 bool cmp(int x,int y) {return x>y;} 8 void dfs(int ans,int sum,int gcd,int now) 9 { 10 if (gcd*sum==tot){cout<<gcd; exit(0);} 11 if (ans==gcd) {dfs(0,sum+1,gcd,1); return;} 12 if (gcd<ans+a[cnt]) return; 13 for (int i=now;i<=cnt;i++) 14 { 15 if (!used[i]&&ans+a[i]<=gcd) 16 { 17 used[i]=1; 18 dfs(ans+a[i],sum,gcd,i+1); 19 used[i]=0; 20 if (ans+a[i]==gcd||ans==0) break; 21 while(a[i]==a[i+1]) i++; 22 } 23 } 24 } 25 int main () 26 { 27 int n; 28 cin>>n; 29 for (int i=1,x;i<=n;i++) 30 { 31 cin>>x; 32 if (x<=50) 33 { 34 a[++cnt]=x; 35 tot+=x; 36 maxx=max(x,maxx); 37 } 38 } 39 sort(a+1,a+cnt+1,cmp); 40 for (int i=maxx;i<=tot/2;i++) 41 { 42 if (tot%i==0) 43 dfs(0,0,i,0); 44 } 45 cout<<tot; 46 }