题目描述
乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过5050。
现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它们的长度。
给出每段小木棍的长度,编程帮他找出原始木棍的最小可能长度。
输入格式
共二行。
第一行为一个单独的整数N表示砍过以后的小木棍的总数,其中N≤65N≤65
(管理员注:要把超过5050的长度自觉过滤掉,坑了很多人了!)
第二行为NN个用空个隔开的正整数,表示NN根小木棍的长度。
输出格式
一个数,表示要求的原始木棍的最小可能长度
输入输出样例
输入 #1复制
9 5 2 1 5 2 1 5 2 1
输出 #1复制
6
思路:深搜的剪枝,关键是要怎么剪枝,容易TLE.关于怎么剪枝都写在了代码里面
代码:
#include<bits/stdc++.h>
using namespace std;
int n,a[105],book[105];
int cnt=0,t,fla=0;
int maxx=-1,minn=1e9,sum=0;
bool cmp(int x,int y)
{
return x>y;
}
//num为已拼当前木棒长度,s为目前要验证的是否可行的木棒长度
//summ为已拼所有木棒的长度,mark为上一根所取木棒的标号,用于剪枝
//k为已拼好的木棒根数
void dfs(int num,int s,int summ,int mark,int k)
{
//拼好了一根,则继续下一根
if(num==s)num=0,k++;
//拼好了所有,就得到了答案
if(summ==sum)fla=1;
//使得找到答案以后不再搜索
if(fla)return;
//当前最短的接上去也不行,就直接可以判断这种拼法不可行
if(minn+num>s)return;
if(num!=0)//不是最新拼了一根
{
for(int i = mark+1; i <= cnt; i++)
{
if(book[i]==0&&a[i]+num<=s)
{
book[i]=1;
dfs(num+a[i],s,summ+a[i],i,k);
book[i]=0;
//如果当前的最优解也没找到答案,则否决这种方案
if(a[i]+num==s)return;
while(a[i]==a[i+1])
i++;
}
}
}
else//最新拼了一根
{
for(int i = k; i <= cnt; i++)
{
if(book[i]==0&&a[i]+num<=s)
{
book[i]=1;
dfs(num+a[i],s,summ+a[i],i,k);
book[i]=0;
//如果新来一根木棒都没拼好的话,那么这种方案已经不可能了
return;
}
}
}
}
int main()
{
scanf("%d",&n);
//除掉长度大于50的木棍
for(int i = 1; i <= n; i++)
{
scanf("%d",&t);
if(t>50)continue;
a[++cnt]=t;
maxx=max(maxx,a[cnt]);
minn=min(minn,a[cnt]);
sum+=a[cnt];
}
sort(a+1,a+1+cnt,cmp);
for(int i = maxx; i <= sum;i++)
{
if(sum%i==0)//能整除的长度才有可能是答案
{
dfs(0,i,0,0,1);
if(fla)
{
printf("%d\n",i);
break;//只需取最小的长度即可
}
}
}
}