题目描述
乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过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(请放心食用)
【题解】搜索+剪枝。剪枝很重要很重要,两个小小的优化就AC!!
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define REP(j,i,n) for(int i=j;i<(n);i++)
const int maxn=70;
int N,A[maxn],ans=0,len,tot;//tot表示当前分法会复原多少根木棒,len表示复原后每根木板的长度
bool done[maxn];
bool dfs(int now,int id,int d){
if(d==tot){
ans=len;return true;}
if(now==0) return dfs(len,0,d+1);//完成了一根
REP(id,i,N)if(done[i]==0&&now>=A[i]){
done[i]=true;
if(dfs(now-A[i],i+1,d))return true;
done[i]=false;
if(now==A[i]||now==len)break; //AC
while(A[i]==A[i+1])i++;//54分
}
return false;
}
bool cmp(int x,int y){
return x>y;
}
int main()
{
int sum=0;
scanf("%d",&N);
for(int i=0;i<N;i++){
scanf("%d",&A[i]);
if(A[i]>50){
i--,N--;
}else sum+=A[i];
}
sort(A,A+N,cmp);
REP(A[0],i,sum+1)
if(sum%i==0){
tot=sum/i,len=i;
if(dfs(len,0,0))break;
}
printf("%d\n",ans);
return 0;
}