poj1011——剪枝dfs搜尋題
阿新 • • 發佈:2019-02-15
題意:
有好多根短棍
他們可以組合成n個長度相同的長棍
求長棍的最短值
粗略參考了網上的1個剪枝技巧:排序,捨棄 之前相同長卻搜失敗的棍子
然後開始自己編寫
發現速度超時, 對著數字推演半天,最終發現len=0,也就是搜新棍子,但是往下搜卻失敗,那麼這根棍子將不存在,這是不可能的,所以直接要直接跳回上級
明天開始回顧圖論,看看華為的那個參賽題到底難不難
#include<stdio.h> #include<string.h> #include<math.h> #define M 2000 int flag[M],stick[M]; int stick_n,want_len,ans_flag,bad_flag; void dfs(int n,int len) { int i,change_flag=1; if(ans_flag==1) //如果已經發現答案,則退出 return ; if(len>want_len) //如果len比假設棍長 大,則退出 return ; if(len==want_len) //如果等於假設棍長,則看n { if(n==stick_n) //相等,說明找到答案 { ans_flag=1; } else len=0; //否則,說明已經找到一組假設棍長組合,len重置0.往下繼續找 } for(i=0;i<stick_n&&ans_flag!=1&&bad_flag!=1;i++) { if(i!=0&&stick[i]==stick[i-1]) //如果之前與自己相同的棍子往下搜時都沒找到,則跳過 { if(change_flag==0) continue; } else change_flag=1; if(flag[i]==1) //如果棍子已被選擇過,則跳過 continue; flag[i]=1;//選擇此棍 dfs(n+1,len+stick[i]); //往下搜 change_flag=0; //說明這個棍子沒找到,那麼與他相同的棍子往下搜肯定也失敗 flag[i]=0; //取消此棍選擇 if(len==0) //如果這個棍子是新棍的第一個,dfs失敗,那麼後面此棍將不存在,這樣不合理 //故跳過之後所有棍子的搜尋 { break; } } } void sort() { int i,j,temp; for(i=0;i<stick_n;i++) for(j=i;j<stick_n;j++) { if(stick[i]<stick[j]) { temp=stick[i]; stick[i]=stick[j]; stick[j]=temp; } } } void main() { int sum,i,max; while(scanf("%d",&stick_n),stick_n!=0) { sum=0; for(i=0;i<stick_n;i++) { scanf("%d",&stick[i]); sum+=stick[i]; flag[i]=0; } sort(); //排序,從大到小 max=stick[0]; //原棍長應該在max到sum之間 ans_flag=0; for(i=max;i<=sum;i++) { if(sum%i!=0) //如果假設原棍長不被sum整除,則捨棄 continue; want_len=i; //假設原棍長 dfs(0,0); if(ans_flag==1) //發現答案,則輸出 { printf("%d\n",i); break; } } } }