标签:
半年前在POJ上遇到过一次剪枝的题目,那时觉得剪枝好神秘。。。今天在网上查了半天资料,终于还是摸索到了一点知识,但是相关资料并不多,在我看来,剪枝是技巧,而不是方法,也就是说,可能一点实用的小技巧,让程序可以少判断一点,这就是剪枝,剪枝无处不在,
搜索的进程可以看作是从树根出发,遍历一棵倒置的树—-搜索树的过程。而所谓的剪枝,顾名思义,就是通过某种判断,避免一些不必要的遍历过程,形象的说,就是减去了搜索树中的某些“枝条”,故称剪枝。
(杭电课件上是这么说的:即剪去解答树上已被证明不可能存在可行解或最优解的子树.)
既
然采用了搜索,剪枝就显得十分的必要,即使就简简单单的设一个槛值,或多加一两条判断,就可对搜索的效率产生惊人的影响。例如N后问题,假如放完皇后再判
断,则仅仅只算到7,就开始有停顿,到了8就已经超过了20秒,而如果边放边判断,就算到了10,也没有停顿的感觉。所以,用搜索一般都就要剪枝。
剪枝至少有两方面,一是从方法上剪枝,如采用分枝定界,启发式搜索等,适用范围比较广;二是使用一些小技巧,这类方法适用性虽不如第一类,有时甚至只能适用一道题,但也十分有效,并且几乎每道题都存在一些这样那样的剪枝技巧,只是每题有所不同而已。
剪枝的原则:
1.正确性:必须保证不丢失正确的结果。
2.准确性:能够尽可能多的减去不能通向正解的枝条
3.高效性:在很多时候,为了加强优化的效果,我们会增加一些判断,这样对程序效率也带来了副作用,所以要考虑剪枝的高效性,否则得不偿失。
最后说一下:剪枝在搜索中用的是非常的广泛的。
(
参照杭电课件第47页一句话:
ACMer们:
为了ACM事业,努力地剪枝吧!!
)
题目我不多说,HDOJ 1010就是一个很好的剪枝题目。
另外,杭电的课件–搜索篇里面也讲了搜索与剪枝。
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 91553 Accepted Submission(s): 24900
#include<iostream> #include<math.h> using namespace std; char s[10][10]; int ax,ay,bx,by,n,m,k; int t[4][2]={1,0,-1,0,0,1,0,-1},vist[10][10],flag; void dfs(int x,int y,int count){ int i,mx,my; if(x==bx&&y==by){ if(k==count) flag=1; return; } if(count>=k) return; if(s[x][y]!=‘X‘){ for(i=0;i<4;i++){ mx=x+t[i][0]; my=y+t[i][1]; if(s[mx][my]!=‘X‘&&mx>=1&&mx<=n&&my>=1&&my<=m&&!vist[mx][my]){ vist[mx][my]=1; dfs(mx,my,count+1); vist[mx][my]=0; if(flag) //注意,在找到了目标之后,就不需要再找!以往编写dfs时,没有注意这点 return; } } } } int main(){ while(scanf("%d%d%d",&n,&m,&k)>0&&(n+m+k)){ int i,count; for(i=1;i<=n;i++){ getchar(); for(int j=1;j<=m;j++){ scanf("%c",&s[i][j]); if(s[i][j]==‘S‘){ ax=i; ay=j; } if(s[i][j]==‘D‘){ bx=i; by=j; } } } getchar(); memset(vist,0,sizeof(vist)); if(abs(ax-bx)+abs(ay-by)>k||(ax+bx+ay+by+k)%2==1){//剪枝 printf("NO\n"); continue; } vist[ax][ay]=1; flag=0; count=0; dfs(ax,ay,count); if(flag==1) printf("YES\n"); else printf("NO\n"); } return 0; }
标签:
原文地址:http://www.cnblogs.com/13224ACMer/p/4799041.html