P1120 小木棍 [数据加强版]
题目描述
乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过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先选大的,后选小的。
2当前条件成立时,不必进行同类搜索(因为这就属于最优解)
3枚举长度时,把数组中直接符合的,预先删去以减少搜索量
#include<iostream> #include<queue> #include<cstdio> #include<algorithm> #include<math.h> #include<string.h> using namespace std; int n,a[69],cnt,c,m; int ans=0,vis[70]; int tot,maxn; bool cmp(const int x,const int y) { return x>y;} void dfs(int h,int last,int sum,int H) { if(last>n) return ; if(sum==0) { printf("%d",ans); exit(0); } for(int i=last+1;i<=n;i++) if(!vis[i]) { if(h+a[i] < H) { vis[i]=1; dfs(h+a[i],i,sum,H); vis[i]=0; } if(h+a[i] == H) { vis[i]=1; dfs(0,0,sum-1,H); vis[i]=0; } if(h+a[i]==H || h==0) break; while( a[i+1] == a[i]) i++; } return ; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&c); if(c<=50) { a[++cnt]=c; tot+=c; maxn=max(maxn,c); } } n=cnt; sort(a+1,a+1+n,cmp); int sum=0; for(int i=maxn;i<=tot;i++)//i每根长度,tot/i,根数 { if(tot%i) continue; sum=tot/i;ans=i; memset(vis,0,sizeof(vis)); for(int j=1;j<=n;j++) if(a[j]==i) { vis[j]=1; sum--; } dfs(0,0,sum,i); } return 0; }