题目描述:给定n个小木棍,将他们接成长度相等的若干根。求接成的木棍长度最小值。
很明显这是一道dfs搜索题。很容易想到所求的值在最长小木棍 和 小木棍总长度 中间。注意不能用二分答案,因为不具有单调性。
只能靠剪枝了。
然而这道题处处都要剪枝才能AC,不愧是经典搜索好题 = =
剪枝一:答案在最长小木棍 和 小木棍总长度 中间,且是总长度的因数。(否则不能接成长度相等的若干根)。
剪枝二:先将小木棍长度从大到小sort一下
在dfs中dfs(int pos,int l,int m) 其中pos表示开始接的位置 ,l表示还需要l的长度使得接成长度相等的木棍,m表示已经接成m根长度相等的木棍了。
若stick[i]==stick[i-1]而used[i-1]=0 此时不需要再算第i根木棍了。
剪枝三:在dfs中 保证stick[i]+l<=len 其中len表示接成木棍的长度
剪枝四:若最长的木棍都不能放入接的序列,那么肯定不能接成了。
身为蒟蒻的我只想到了剪枝一和剪枝三,无限RE。真是见RE君,眼泪掉下来 = =
蒟蒻加油 ↖(^ω^)↗
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int n ,num[65] ,len ,cnt ,sum;
bool vis[65] ,flag ;
bool dfs(int k,int l,int m)
{
if(m==cnt)return 1;
if(l==len)return dfs(0,0,m+1);
int pre=0;
for(int i=k;i<n;++i)
{
if(!vis[i]&&num[i]!=pre&&num[i]+l<=len) \\ 剪枝二 剪枝三
{
pre=num[i];
vis[i]=1;
if(dfs(i+1,l+num[i],m))
return 1;
vis[i]=0;
if(k==0)return 0; \\ 剪枝四
}
}
return 0;
}
bool cmp(int a,int b)
{
return a>b;
}
int main()
{
while(~scanf("%d",&n)&&n)
{
sum=0;
flag=1;
for(int i=0;i<n;++i)
{
scanf("%d",&num[i]);
sum+=num[i];
}
sort(num,num+n,cmp);
for(len=num[0];len<sum;++len) \\ 剪枝一
if(sum%len==0)
{
cnt=sum/len;
memset(vis,0,sizeof(vis));
if(dfs(0,0,0))
{
flag=0;
printf("%d\n",len);
break;
}
}
if(flag)
printf("%d\n",sum);
}
return 0;
}