1. 程式人生 > 實用技巧 >POJ 1011 Sticks(DFS+剪枝)

POJ 1011 Sticks(DFS+剪枝)

題目連結:http://poj.org/problem?id=1011

剪枝策略:

1.優化搜尋順序:

將每一段木棒的長度從大到小排序。

2.排除等效冗餘:

(1)設兩根木棒長度分別為x,y,且x<y,那麼先拼上x再拼y和先拼y再拼x是等效的,只需要搜尋其中的一種。那麼可以限制選的順序為遞減的。

(2)對於當前的木棒,可以記錄最近一次嘗試拼入的木棍長度。如果分支搜尋失敗回溯,不再向該木棒中加入其他長度相同的木棍(因為必定也會失敗)。

(3)如果在當前原始木棒嘗試拼入第一根木棍的遞迴就返回失敗,那麼直接判定整個分支失敗,立即回溯。因為在拼入這根木棒前,所有的原始木棒都是空的。木棒在拼當前木棒中失敗,在拼其他木棒中一樣會失敗。

(4)如果在當前原始木棒中拼入一根木棍後,木棒恰好被拼接完整,並且接下來拼接剩餘原始木棒的遞迴分支失敗,那麼可以判定整個分支失敗。(可以用貪心來解釋)

AC程式碼:

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<algorithm>
 4 #include<cstring>
 5 using namespace std;
 6 const int N=80;
 7 int n,len,cnt,val,sum;
 8 int vis[N],a[N];
 9 bool cmp(int
x,int y){ 10 return x>y; 11 } 12 bool DFS(int stick,int now,int last){ 13 if(stick>cnt) return 1; 14 if(now==len) return DFS(stick+1,0,1); 15 int fail=0; 16 for(int i=last;i<=n;i++){ 17 if(!vis[i]&&now+a[i]<=len&&fail!=a[i]){ 18 vis[i]=1
; 19 if(DFS(stick,now+a[i],i+1)) return 1; 20 fail=a[i]; 21 vis[i]=0; 22 if(now==0||now+a[i]==len) return 0; 23 } 24 } 25 return 0; 26 } 27 int main(){ 28 while(~scanf("%d",&n)&&n){ 29 sum=val=0; 30 for(int i=1;i<=n;i++) scanf("%d",&a[i]),val=max(val,a[i]),sum+=a[i]; 31 sort(a+1,a+n+1,cmp); 32 for(len=val;len<=sum;len++){ 33 if(sum%len) continue; 34 cnt=sum/len; 35 memset(vis,0,sizeof(vis)); 36 if(DFS(1,0,1)) break; 37 } 38 printf("%d\n",len); 39 } 40 return 0; 41 }
AC程式碼