【题目】
【分析】
一道很经典的深搜剪枝题
这里给出几个小剪枝(可以去 l u o g u luogu luogu 题解第一篇去看,那个特别详细):
-
长度的范围明显在 m a x { a i } max \{ a_i\} max{ai}~ s u m sum sum 之间
-
长度从大到小开始搜,长度小的比较灵活,到后面容易拼凑(深度大的状态多)
-
在某组搜索中长度一样的不用重复枚举,因为排序过,之前枚举不合适现在选择也不会合适。
-
重要剪枝:对于某个目标 l e n len len,在每次构建新的长度为 l e n len len 的原始木棒时,检查新棒的第一根 s t i c k i stick_i sticki,若在搜索完所有 s t i c k stick stick 后都无法组合,则说明 s t i c k i stick_i sticki 无法在当前组合方式下组合,不用往下搜索(往下搜索会令 s t i c k i stick_i sticki 被舍弃),直接返回上一层
【代码】
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 105
using namespace std;
int n,sum,len,tot,a[N],vis[N];
bool comp(int a,int b) {return a>b;}
bool dfs(int now,int length,int last)
{
if(now>tot) return true;
if(length==len) return dfs(now+1,0,1);
int i,fail=0;
for(i=last;i<=n;++i)
{
if(!vis[i]&&length+a[i]<=len&&fail!=a[i])
{
vis[i]=true;
if(dfs(now,length+a[i],i+1))
return true;
fail=a[i];
vis[i]=false;
if(length==0)
return false;
}
}
return false;
}
int main()
{
// freopen("sticks.in","r",stdin);
// freopen("sticks.out","w",stdout);
int i;
scanf("%d",&n);
for(i=1;i<=n;++i)
scanf("%d",&a[i]),sum+=a[i];
sort(a+1,a+n+1,comp);
for(len=a[1];len<=sum;++len)
{
if(sum%len) continue;
memset(vis,0,sizeof(vis));
tot=sum/len;
if(dfs(1,0,1)) break;
}
printf("%d",len);
// fclose(stdin);
// fclose(stdout);
return 0;
}