把博客當作一個記錄代碼的地方吧。這個題想一想還真的挺不錯的,能提高對回溯法的理解。題意不難理解,一堆切開的小木棒,然後把這些小木棒合起來,找到這些合起來的小木棒的最小長度,最關鍵的一點這些小木棒合起來的長度都是一樣的。
我開始的思路試枚舉多少根小木棒,然後通過總的除以根數就得到了小木棒的長度,然後一一去判斷,結果寫着寫着怎麼也不會寫了,就從網上借鑑了大神們的代碼。思路:直接枚舉長度,然後通過遞歸求根數然後判斷相乘之後能否等於總長度即可,這裏要注意的就是枚舉的長度一定要大於等於木棒的最大長度,小於等於總長度。網上的大神貌似都用到了剪枝,但我覺得剪不剪都一樣(可能是自己太弱了,看不出區別)所以就沒有用到剪枝。不多說,上代碼:
#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;
}