深搜部分和之前的POJ2362差不多,只是有几处需要额外的剪枝。
【思路】排序后从最短木棒开始搜索至木棒长总和,如果木棒长总和sum能整除当前棒长,则进入深搜。
【剪枝】先前POJ2362的剪枝部分不再重提,这里只讲额外的几处(我们称切断后的棒为木棒,切断前的棒为原棒):
1.如果所有木棒等长,即排序后stick[0]=stick[n-1],则直接输出棒长;
2.如果当前搜索的棒长即是棒长总和,无需进入深搜子程序,直接输出;
3.如果深搜中当前长度的木棒不能选择,则略去同一层中相同长度的木棒;
4.如果当前是重新开始组成一个原棒,即len=0时。如果可以组成原棒,则取frm时必然能返回真(因为组成原棒的顺序是无所谓的);若选取frm时仍然无法组成,则说明不能组成原棒,直接退出深搜,返回假。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 const int MAXN=64+5; 7 int n,sl; 8 int stick[MAXN]; 9 int vis[MAXN]; 10 11 int dfs(int side,int frm,int len) 12 { 13 if (1==side) return 1; 14 int last=-1; 15 for (int i=frm;i>=0;i--) 16 if (!vis[i] && stick[i]!=last) 17 { 18 vis[i]=1; 19 if (sl==len+stick[i]) 20 { 21 if (dfs(side-1,n-1,0)) return 1; 22 } 23 else if (sl>len+stick[i]) 24 { 25 if (dfs(side,i-1,len+stick[i])) return 1; 26 } 27 vis[i]=0; 28 last=stick[i]; 29 if (len==0) break; 30 } 31 return 0; 32 } 33 34 int main() 35 { 36 while (scanf("%d",&n)) 37 { 38 if (0==n) break; 39 int sum=0; 40 for (int i=0;i<n;i++) 41 { 42 scanf("%d",&stick[i]); 43 sum+=stick[i]; 44 } 45 sort(stick,stick+n); 46 if (stick[0]==stick[n-1]) 47 { 48 cout<<stick[0]<<endl; 49 continue; 50 } 51 for (int i=stick[0];i<=sum;i++)//i代表每一根木棒的长度 52 if (0==sum%i) 53 { 54 sl=i; 55 memset(vis,0,sizeof(vis)); 56 if (i==sum || dfs(sum/i,n-1,0)) 57 { 58 cout<<i<<endl; 59 break; 60 } 61 } 62 } 63 return 0; 64 }