/*
推荐题型:五星 经典DFS + 剪枝
题意:长度相同的木棒被分成许多段,求木棒原来状态的最短长度
此题重在剪枝,主要剪枝思路有:
使用数组a存储被分解成的各个部分的长度,木棒的每段被称之为s
①搜索范围从max到sum,且必须能被sum整除
②为避免重复,组合成木棒的s从大到小排序,每根木棒的第一个s,也要求从大到小排序
③在某层搜索中,如果a[i]没有使用,且a[i]==a[i+1],则a[i+1]也要舍弃
④搜索中,木棒的第一个s,a[i]为可满足的最大值,如果尝试失败,则直接退出,返回到上一层搜索
完全参考:心如止水C++博客
*/
#include <cstdio>
#include <cstdlib>
#include <cstring>
// #define LOCAL
#ifdef LOCAL
#include<time.h>
#endif
int a[60];
bool used[60];
int aim,num;
int n;
int cmp(const void *a,const void *b)
{
int *pa=(int *)a;
int *pb=(int *)b;
return (*pb)-(*pa);
}
bool dfs(int stick,int len,int pos)
{
bool sign=(len==0?true:false);
if(stick==num) return true;//这里实际只需要到num即可,因为aim可被sum整除,所以后面的不需要再计算
for(int i=pos+1;i<n;i++)
{
if(used[i]) continue;
if(len+a[i]==aim)
{
used[i]=true;
if(dfs(stick+1,0,-1))
return true;
used[i]=false;
return false;
}
else if(len+a[i]<aim)
{
used[i]=true;
if(dfs(stick,len+a[i],i))
return true;
used[i]=false;
if(sign) return false;
while(i<n-1 && a[i]==a[i+1])i++;
}
}
return false;
}
int main()
{
//freopen("data.in","r",stdin);
while(scanf("%d",&n) && n)
{
int max,sum;
max=sum=0;
for(int i=0;i<n;i++)
{
scanf("%d",&a[i]);
if(a[i]>max)
max=a[i];
sum+=a[i];
}
qsort(a,n,sizeof(a[0]),cmp);
for(aim=max;aim<=sum;aim++)
{
if(sum%aim==0)
{
num=sum/aim;
memset(used,0,sizeof(used));
if(dfs(1,0,-1))
{
printf("%d\n",aim);
break;
}
}
}
}
#ifdef LOCAL
printf("used time = %.3lf\n",(double)clock()/CLOCKS_PER_SEC);
#endif
return 0;
}
307 Sticks(*****)经典DFS+剪枝
最新推荐文章于 2025-06-18 08:55:40 发布