把博客当作一个记录代码的地方吧。这个题想一想还真的挺不错的,能提高对回溯法的理解。题意不难理解,一堆切开的小木棒,然后把这些小木棒合起来,找到这些合起来的小木棒的最小长度,最关键的一点这些小木棒合起来的长度都是一样的。
我开始的思路试枚举多少根小木棒,然后通过总的除以根数就得到了小木棒的长度,然后一一去判断,结果写着写着怎么也不会写了,就从网上借鉴了大神们的代码。思路:直接枚举长度,然后通过递归求根数然后判断相乘之后能否等于总长度即可,这里要注意的就是枚举的长度一定要大于等于木棒的最大长度,小于等于总长度。网上的大神貌似都用到了剪枝,但我觉得剪不剪都一样(可能是自己太弱了,看不出区别)所以就没有用到剪枝。不多说,上代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxed=100+10;
int panDuan[maxed],n,muBang[maxed],changDu,zong;
int main()
{
bool slove(int,int,int);
bool cmp(int,int);
while(scanf("%d",&n)!=EOF&&n){
//memset(panDuan,0,sizeof(panDuan));
memset(muBang,0,sizeof(muBang));
int t;
zong=0;
for(int i=0;i<n;i++){
scanf("%d",&t);
muBang[i]=t;
zong+=t;
}
sort(muBang,muBang+n,cmp);//对木棒长度进行排序,这样每次都从最大的开始找,会节省很多时间。
for(changDu=muBang[0];changDu<=zong;changDu++)
if(!(zong%changDu)){
//cout<<2<<endl;
memset(panDuan,0,sizeof(panDuan));
if(slove(0,0,0))
break;
}
printf("%d\n",changDu);
}
return 0;
}
bool cmp(int x,int y)
{
return x>y;
}
bool slove(int now,int geShu,int cur)//now当前长度,geShu当前的木棒根数,cur当前枚举到的位置(这里一定要写位置,如果每次都从0开始枚举会出现时间溢出)
{
//cout<<1<<endl;
if(geShu*changDu==zong)
return true;
for(int i=cur;i<n;i++){
if(panDuan[i])
continue;
// if(i&&!panDuan[i-1]&&muBang[i]==muBang[i-1])
// continue;
if(now+muBang[i]==changDu){
panDuan[i]=1;
if(slove(0,geShu+1,0))
return true;
panDuan[i]=0;
return false;
}
else if(now+muBang[i]<changDu){
panDuan[i]=1;
if(slove(now+muBang[i],geShu,i+1))
return true;
panDuan[i]=0;
if(now==0)
return false;
}
}
return false;
}