標籤:dfs
轉載請註明出處:http://blog.csdn.net/u012860063
題目連結:http://poj.org/problem?id=1011
Description
George took sticks of the same length and cut them randomly until all parts became at most 50 units long. Now he wants to return sticks to the original state, but he forgot how many sticks he had originally and how long they were originally. Please help him and design a program which computes the smallest possible original length of those sticks. All lengths expressed in units are integers greater than zero.
Input
The input contains blocks of 2 lines. The first line contains the number of sticks parts after cutting, there are at most 64 sticks. The second line contains the lengths of those parts separated by the space. The last line of the file contains zero.
Output
The output should contains the smallest possible length of original sticks, one per line.
Sample Input
95 2 1 5 2 1 5 2 141 2 3 40
Sample Output
65
Source
Central Europe 1995
題目的大意:是給了你有限個棍子以及每個棍子的長度,而且所有的棍子都是由有限個長度相同的棍子截斷得到的,讓你求被截棍子的最小長度,本題的演算法是深搜,當然需要幾個剪枝的!
代碼如下:
#include <iostream>#include <algorithm>using namespace std;int sticks[65];int used[65];int n,len;bool dfs(int i,int l,int t)//i為當前試取的棍子序號,l為要拼成一根完整的棍子還需要的長度,t初值為所有棍子總長度 { if(l==0) { t -= len;//如果len為所有棍子的和 if(t == 0)return true; for(i = 0; used[i]; i++); //剪枝1:搜尋下一根大棍子的時候,找到第一個還沒有使用的小棍子開始 used[i]=1; //由於排序過,找到的第一根肯定最長,也肯定要使用,所以從下一根開始搜尋 if(dfs(i+1,len-sticks[i],t))return true; used[i]=0;//回溯 t+=len; } else { for(int j = i; j < n; j++) { if(j>0 && (sticks[j]==sticks[j-1]&&!used[j-1])) //剪枝2:前後兩根長度相等時,如果前面那根沒被使用,也就是由前面那根 continue; //開始搜尋不到正確結果,那麼再從這根開始也肯定搜尋不出正確結果,此剪枝威力較大 if(!used[j] && l>=sticks[j]) //剪枝3:最簡單的剪枝,要拼成一根大棍子還需要的長度L>=當前小棍子長度,才能選用 { l-=sticks[j]; used[j]=1; if(dfs(j,l,t))return true; l+=sticks[j];//回溯 used[j]=0; if(sticks[j]==l) //剪枝4:威力巨大的剪枝,程式要運行到此處說明往下的搜尋失敗,若本次的小棍長度剛好填滿剩下長度,但是後 break; //面的搜尋失敗,則應該返回上一層 } } } return false;}bool cmp(const int a, const int b){ return a>b; }int main(){ while(cin>>n&&n) { int sum=0;int max = -1; for(int i = 0; i < n; i++) { cin>>sticks[i]; sum += sticks[i]; used[i] = 0;if(sticks[i] > max)//找出最長的棍子max = sticks[i]; } sort(sticks,sticks+n,cmp); //剪枝5:從大到小排序後可大大減少遞迴次數 bool flag=false; for(len = max; len <= sum/2; len++) //剪枝6:大棍長度一定是所有小棍長度之和的因數,且最小因數應該不小於小棍中最長的長度 { if(sum%len == 0) { if(dfs(0,len,sum)) { flag=true; cout<<len<<endl; break; } } } if(!flag) cout<<sum<<endl; } return 0;}