这就是一道明显的爆搜题(人家洛谷也说了,,,),只是需要几个小小的优化,接下来为大家介绍一下:
1、将木棍先排个序(用处后面会讲),记住 长度>50 的要去掉
2、因为每一根的长度都不大于50,所以可以用桶装,既省空间也省时间
3、……先上代码吧,要不然直接讲比较抽象(其实是我口才不好)……
————————————(华丽的分割线)————————————————
#include
#include
#include
int n=0,m;
int a[110];//桶
int p=0;//木棍总长度
int max=0,min=51;//最长的木棍的长度以及最短的木棍的长度
int ans;//记录当前成功拼接了几根木棍,在dfs中用到
void dfs(int x,int y,int z)//x表示每根木棍的期望长度,y表示现在拼成的长度,z表示上一次使用的木棍的长度
{
if(ans*x==p)//假如拼接成功
{
printf("%d",x);
exit(0);//直接结束,此时一定是最优解,因为他要的是最小的解
//而我们是从小到大枚举的,第一个解必然是最优解
}
for(int i=z;i>=min;i--)//因为较长的木棍更难拼,所以从长的先开始
{
if(a[i]&&y+i<=x)//假如还有长度为i的木棍以及拼接起来不会超过期望长度的话
{
y+=i;
if(y==x)ans++,y=0;
a[i]--;
if(y==0)dfs(x,y,max);//如果拼接成功,则z要从max开始
else dfs(x,y,i);
a[i]++;
if(ans>0&&y==0)y=x-i,ans--;
else y-=i;
if(y==0)break;//最重要的优化1:见下文
if(y+i==x)break;//最重要的优化2:同上
}
}
}
int main()
{
scanf("%d",&m);
memset(a,0,sizeof(a));//一定要记得初始化!!!
for(int i=1;i<=m;i++)
{
int x;
scanf("%d",&x);
if(x<=50)//过滤掉超过50的
{
a[x]++,p+=x;
max=maxx?x:min;
}
}
for(int i=max;i<=p/2;i++)//枚举原本木棍的长度,用dfs尝试是否能拼接成功
//由于原本木棍的长度不可能比最长的木棍长度要短,所以从max开始
//以及原本木棍的长度一定能整除总长度(商为1的情况下面会处理),所以假如i>p/2的时候
//i一定不能整除p,所以没必要dfs,直接跳过
{
if(p%i==0)//如果不能整除则跳过(不能整除则说明会有余数,也就是多余的木棍)
{
ans=0;//一定要记得初始化!!!
dfs(i,0,max);
}
}
printf("%d",p);//假如上面未成功,就只能把全部拼在一起了
}
最重要的优化1:首先要思考,什么时候y==0,当然是刚开始拼接新的一根木棍时,而这条语句在dfs下面,也就是说拼接没有成功,才会到达这里,也就剩下那么些木棍,如果既然拼接都不成功了,那么也就没有必要尝试其他的了,于是break
优化2:上面y==0 break之后,就会到达上一根木棍的最后拼接的时候,那前面都知道是不可以的了,那也没有必要继续了,于是也break
以上就是我的想法,如果有人有更好的优化的话,欢迎评论