http://poj.org/problem?id=1011
這題主要在剪枝上下功夫,十分十分經典的一道搜尋,方法是從n到1倒著來搜,當在某一處時,所有的stick能夠完美組成sum/i這一長度,就break。
經典題,非常好,這題對遞迴、搜尋會有更深刻理解。
#include <vector>#include <list>#include <map>#include <set>#include <string.h>#include <deque>#include <stack>#include <bitset>#include <algorithm>#include <functional>#include <numeric>#include <utility>#include <sstream>#include <iostream>#include <iomanip>#include <cstdio>#include <cmath>#include <cstdlib>#include <ctime>using namespace std;#define LL long long#define pi acos(-1)#define N 5000#define INF 999999999#define eps 1e-8//****************************************//poj 1011 dfs//Copyright@leolin All rights reserved.//****************************************int a[100];bool vis[100];int n,ans;bool dfs(int used,int pos,int len){ int i,j; if(used==n)return true; for(i=pos;i<n;i++) { if(vis[i]) continue; if(len+a[i]<ans) { vis[i]=true; if(dfs(used+1,i+1,len+a[i])) return true; vis[i]=false;//如果dfs(used+1,i+1,len+a[i])返回false,則第i根不可用,標記為false while(a[i]==a[i+1] && i+1<n)//如果前面一個相等長度的棍子沒有用上,那麼這個也用不上,重要剪枝 { i++; }if(len==0) return false;//如果當前長度為0,證明沒有合適的,return false } else if(len+a[i]==ans) { vis[i]=true; if(dfs(used+1,0,0)) return true; vis[i]=false; return false; } } return false;}int main(){ while(scanf("%d",&n)&&n) { int i,j,k; int sum=0,maxm=0; for(i=0;i<n;i++) { scanf("%d",&a[i]); sum+=a[i]; maxm=max(maxm,a[i]); } sort(a,a+n,greater<int>() );//從大到小排序可減少遞迴次數 for(i=n;i>0;i--) { if(sum%i==0 && (sum/i)>=maxm) { ans=sum/i; memset(vis,false,sizeof(vis)); if(dfs(0,0,0)) { printf("%d\n",ans); break; } } } } return 0;}