思路:dfs+剪枝算法
1)要确定好target,也就是um of sticks的约数且要大于最大的木棍
2)木棍排序,从大到小排
3)在满足一个target的任务中,因为顺序排列,所以重复元素,前面没选的,这一次也不选,剪枝
4)在满足一个target的任务中,如果当前最长的木棍满足失败,则整条枝失败,因为我们从小到大排列,会越来越小
#include<bits/stdc++.h>
using namespace std;
#define ul unsigned long
#define ll long long
int q[65];
int flag;///标记
int minn; ///符合条件的最小的木棒
int vis[65]; ///标记一下是否用过该木棒
int n;
int cmp(int a,int b)
{
return a>b;
}
///将和minn相同长度的拼接木棒放在一个格子里面
void dfs(int deep,int len,int num) /// 已经放的格子数,目前所拼接木棒的长度, 当前正在选择的小棒的序号
{
if(flag)
{
return ;
}
if(len==0)//len == 0说明前面都已经完成,开始新的一轮
{
int i=1;
while(vis[i])
{
i++;
}
vis[i]=1;
dfs(deep+1,len+q[i],i+1);
if(flag)
{
return;
}
vis[i]=0;//目前最长棍都失败,不用继续,直接退出,失败。
return;
}
if(len==minn)
{
if(deep==n)//格子填完,表示所有木棍被选,成功
{
flag=1;
}
else
{
dfs(deep,0,1);//还未填完,开始新的一轮
if(flag)
{
return;
}
}
return ;
}
for(int i=num;i<=n;i++)//不是新开始,也不是刚好结束,那就是要找棍子
{
if(vis[i]==0&&q[i]+len<=minn)
{
if(vis[i-1]==0&&q[i]==q[i-1])//上一根一样长且没被选过,那这一根也没必要
{
continue;
}
vis[i]=1;
dfs(deep+1,len+q[i],i+1);
if(flag)
{
return;
}
vis[i]=0;//失败,放下棍子
if(len+q[i]==minn) return ;//满足了,但是前面验证过失败了,所以直接返回
if(flag)
{
return;
}
}
}
if(flag)
{
return;
}
}
int main()
{
while(~scanf("%d",&n)&&n)
{
int sum=0;
for(int i=1;i<=n;i++)
{
scanf("%d",&q[i]);
sum+=q[i];
}
sort(q+1,q+1+n,cmp);
for(int i=q[1];i<=sum;i++)
{
if(sum%i!=0)
{
continue;
}
flag=0;
memset(vis,0,sizeof(vis));
minn=i;
dfs(0,0,1);
if(flag)
{
printf("%d\n",i);
break;
}
}
}
}