https://www.luogu.org/problem/show?pid=1120
题目描述
乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过50。
现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它们的长度。
给出每段小木棍的长度,编程帮他找出原始木棍的最小可能长度。
输入输出格式
输入格式:
输入文件共有二行。
第一行为一个单独的整数N表示砍过以后的小木棍的总数,其中N≤65
(管理员注:要把超过50的长度自觉过滤掉,坑了很多人了!)
第二行为N个用空个隔开的正整数,表示N根小木棍的长度。
输出格式:
输出文件仅一行,表示要求的原始木棍的最小可能长度
输入输出样例
输入样例#1:
9 5 2 1 5 2 1 5 2 1
输出样例#1:
6
说明
2017/08/05
数据时限修改:
-#17 #20 #22 #27 四组数据时限500ms
-#21 #24 #28 #29 #30五组数据时限1000ms
其他时限改为200ms(请放心食用)
从大到小排序(方便剪枝,小木棒拼接更灵活),搜索 当前未拼得的原木棒的长度,已经凑出的原木棒根数,当前拼出的根数。
1 #include <algorithm> 2 #include <cstdio> 3 4 const int N(66); 5 int n,len[N],tot,sum,ans; 6 bool cmp(int a,int b) 7 { 8 return a>b; 9 } 10 11 bool vis[N]; 12 bool DFS(int nowlenth,int cnt,int num) 13 { 14 if(cnt==tot) return 1; 15 if(!nowlenth) 16 if(DFS(ans,cnt+1,1)) return 1; 17 for(int i=num; i<=n; ++i) 18 { 19 if(vis[i]||len[i]>nowlenth) continue; 20 vis[i]=1; 21 if(DFS(nowlenth-len[i],cnt,i+1)) return 1; 22 vis[i]=0; 23 if(len[i]==nowlenth||nowlenth==ans) break; 24 //如果当前长度不能拼出下一根木棒,最大的失效则没有可以全部拼出的情况 25 for( ;len[i+1]==len[i]; ) ++i;//剪去等长的木棒 26 } 27 return 0; 28 } 29 30 inline void read(int &x) 31 { 32 x=0; register char ch=getchar(); 33 for(;ch>'9'||ch<'0';) ch=getchar(); 34 for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; 35 } 36 37 int AC() 38 { 39 read(n); 40 for(int i=1,x; i<=n; ++i) 41 { 42 read(x); 43 if(x>50) 44 { 45 i--;n--; 46 continue; 47 } 48 len[i]=x,sum+=x; 49 } 50 std::sort(len+1,len+n+1,cmp); 51 for(ans=len[1]; ans<=sum; ++ans) 52 { 53 if(sum%ans) continue; 54 tot=sum/ans; 55 if(DFS(ans,0,1)) 56 { 57 printf("%d ",ans); 58 return 0; 59 } 60 } 61 return 0; 62 } 63 64 int Hope=AC(); 65 int main(){;}