标签:
今天搞了一下传说中的经典搜索题——poj1011,果然里面充斥着各种巧妙的剪枝,做完之后回味一下还是感觉构思太巧妙,所以总结记录一下加深理解。
原题:http://poj.org/problem?id=1011
刚开始接触搜索的初学者面对这道题可能感觉无从下手,即便是告诉了要用深搜解决这道题,也不知道怎么用,我现在也对搜索有了更多的理解与体会,其实不要把搜索只理解为在一个地图上找点,其实搜索更可以抽象为当面对多个选择的时候如何抉择,深搜就是先认准一个方向走下去,不行再回来,走别的路;广搜就是把每一次能做的选择都试一遍。所以,这道拼木棍的题就是一道很好的深搜题。我们不知道哪根木棍可组合进来,那不如就按从前往后的顺序一个一个试。
唠叨了半天,终于该放代码了。。简单的注释我写在程序里了,稍微长一点的解释,我程序里有序号,我把详细的解释写在外面,大家对一下序号来看。
PS:我不能确定我写的已经是优化到最好了,也希望有更好想法的小伙伴可以在评论里教下我,谢谢~如果喜欢别忘了点赞哟~
1 #include<stdio.h> 2 #include<string.h> 3 int sticks[70],book[70];//一个存木棍,一个标记是否使用 4 int n,len,num;//len是合并后每根木棍的长度,num是合并后的木棍数目 5 //手写快排,不太会C++。。。 6 void quicksort(int left,int right){ 7 if(left>right) 8 return; 9 int temp=sticks[left],i=left,j=right; 10 while(i!=j){ 11 while(sticks[j]<=temp&&j>i) 12 j--; 13 while(sticks[i]>=temp&&j>i) 14 i++; 15 if(i<j){ 16 int t=sticks[i]; 17 sticks[i]=sticks[j]; 18 sticks[j]=t; 19 } 20 } 21 sticks[left]=sticks[i]; 22 sticks[i]=temp; 23 quicksort(left,i-1); 24 quicksort(i+1,right); 25 } 26 int dfs(int cur,int k,int cnt){//cur是正在合并的木棍的长度,k是木棍的下标,cnt是合并好的木棍数 27 if(cnt==num)//完成要求的情况 28 return 1; 29 if(cur==len)//合并好一根木棍的情况 30 return dfs(0,0,cnt+1); 31 int i,pre=0;//i是木棍下标,pre保存重复木棍 32 for(i=k;i<n;i++){ 33 if(book[i]==0&&sticks[i]+cur<=len&&sticks[i]!=pre){//1 34 pre=sticks[i]; 35 book[i]=1; 36 if(dfs(sticks[i]+cur,i+1,cnt))//2 37 break; 38 book[i]=0; 39 if(k==0)//3 40 return 0; 41 } 42 } 43 if(i==n) 44 return 0; 45 else 46 return 1; 47 } 48 int main(){ 49 while(scanf("%d",&n)!=EOF&&n){ 50 int sum=0;//总长度 51 for(int i=0;i<n;i++){ 52 scanf("%d",&sticks[i]); 53 sum+=sticks[i]; 54 } 55 quicksort(0,n-1);//注意要从大到小排序,因为合并后木棍的长度一定大于原来最长的 56 for(len=sticks[0];len<=sum/2;len++){//剪枝,从最大的长度开始枚举,这里大于sum/2归并为了合成一根木棍的情况 57 if(sum%len==0){//长度是总长因数才符合要求 58 num=sum/len; 59 memset(book,0,sizeof(book)); 60 if(dfs(0,0,0)) 61 break; 62 } 63 } 64 if(len>sum/2)//一根木棍的情况 65 printf("%d\n",sum); 66 else 67 printf("%d\n",len); 68 } 69 return 0; 70 }
标签:
原文地址:http://www.cnblogs.com/Leo_wl/p/4921872.html