标签:
今天搞了一下传说中的经典搜索题——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