hdu1455Sticks深搜+剪枝
阿新 • • 發佈:2018-12-13
題意:
有多個相同長度的木棍,將它們隨機切成n個小木棍,現在要把它們還原,問原先的木棍長度最短可以是多少 小木棍的長度最大為50,n最大為64
題解:
把給定的長度木棍排序從小到大
列舉長度,從最小值不斷+1,先判斷是否能被其總長度整除,能整除進行深搜,不能則繼續
深搜過程:
深搜引數:標記陣列,湊木棍當前長度,目標長度,當前位置,木棍當前用量;
如果len+stick[i]<目標長度,繼續深搜;
如果等於目標長度,繼續深搜,標記當前位置為0;
p為本次深搜所用的不合要求的長度,剪枝
flag[i]標記已用木棍;
#include <cstdio> #include <cstdlib> #include <cstring> #define MAX 70 int n; int sticks[MAX]; int sum_len; int cmp(const void *a,const void *b) { return *((int *)b)-*((int *)a); } bool dfs(bool *flag,int len,int a_len,int s,int num) //flag標記,len當前長度,a_len目標單根長度,s當前搜尋位置,num當前總用量 { //標記,當前長度,目標長度,搜尋位置,當前用量; if(num==n) return true;//結束; int p=-1; //高效剪枝,不遞迴相同且不可用的枝條 for(int i=s; i<n; i++) { if(flag[i] || p==sticks[i]) continue; flag[i]=1;//標記已經用過; if(len+sticks[i]<a_len) { //小於目標長度,繼續深搜; if(dfs(flag,len+sticks[i],a_len,i,num+1)) return true;//注意不成立還需要繼續下一個小木段 else p=sticks[i];//代表這種長度不行...剪枝,只在本次深搜中發揮作用; } else if(len+sticks[i]==a_len) { //這個已經滿足; //繼續深搜下一個長度,從0開始; if(dfs(flag,0,a_len,0,num+1))return true;//一個木棍滿足了條件,0位置?; else p=sticks[i];//剪枝...這一個行,但是下一個又不行,也不滿足; } flag[i]=0;//回溯; if(len==0)//剪枝,當沒有能夠組合出木棍,說明木棍可能已經用完了。 break; } return false; } int main() { bool flag[MAX];//定義flag陣列; while(~scanf("%d",&n) && n) { sum_len=0; for(int i=0; i<n; i++) { scanf("%d",&sticks[i]); sum_len+=sticks[i]; }//得到所有木棒的總長度; qsort(sticks,n,sizeof(int),cmp);//按照給定木棒長度排序; int MinLen=sum_len; for(int i=sticks[0]; i<=sum_len; i++) //從最短的木棒長度列舉到所有長度之和i++; { if(sum_len%i==0) { memset(flag,0,sizeof(flag)); // if(dfs(flag,0,i,0,0)) //長度為i { MinLen=i; break; } } } printf("%d\n",MinLen); } }