半年前在POJ上遇到过一次剪枝的题目,那时觉得剪枝好神秘。。。今天在网上查了半天资料,终于还是摸索到了一点知识,但是相关资料并不多,在我看来,剪枝是技巧,而不是方法,也就是说,可能一点实用的小技巧,让程序可以少判断一点,这就是剪枝,剪枝无处不在,
搜索的进程可以看作是从树根出发,遍历一棵倒置的树—-搜索树的过程。而所谓的剪枝,顾名思义,就是通过某种判断,避免一些不必要的遍历过程,形象的说,就是减去了搜索树中的某些“枝条”,故称剪枝。
(杭电课件上是这么说的:即剪去解答树上已被证明不可能存在可行解或最优解的子树.)
既
然采用了搜索,剪枝就显得十分的必要,即使就简简单单的设一个槛值,或多加一两条判断,就可对搜索的效率产生惊人的影响。例如N后问题,假如放完皇后再判
断,则仅仅只算到7,就开始有停顿,到了8就已经超过了20秒,而如果边放边判断,就算到了10,也没有停顿的感觉。所以,用搜索一般都就要剪枝。
剪枝至少有两方面,一是从方法上剪枝,如采用分枝定界,启发式搜索等,适用范围比较广;二是使用一些小技巧,这类方法适用性虽不如第一类,有时甚至只能适用一道题,但也十分有效,并且几乎每道题都存在一些这样那样的剪枝技巧,只是每题有所不同而已。
剪枝的原则:
1.正确性:必须保证不丢失正确的结果。
2.准确性:能够尽可能多的减去不能通向正解的枝条
3.高效性:在很多时候,为了加强优化的效果,我们会增加一些判断,这样对程序效率也带来了副作用,所以要考虑剪枝的高效性,否则得不偿失。
最后说一下:剪枝在搜索中用的是非常的广泛的。
(
参照杭电课件第47页一句话:
ACMer们:
为了ACM事业,努力地剪枝吧!!
)
题目我不多说,HDOJ 1010就是一个很好的剪枝题目。
另外,杭电的课件–搜索篇里面也讲了搜索与剪枝。
Tempter of the Bone
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 91553 Accepted Submission(s): 24900
Problem Description
The
doggie found a bone in an ancient maze, which fascinated him a lot.
However, when he picked it up, the maze began to shake, and the doggie
could feel the ground sinking. He realized that the bone was a trap, and
he tried desperately to get out of this maze.
The maze was a
rectangle with sizes N by M. There was a door in the maze. At the
beginning, the door was closed and it would open at the T-th second for a
short period of time (less than 1 second). Therefore the doggie had to
arrive at the door on exactly the T-th second. In every second, he could
move one block to one of the upper, lower, left and right neighboring
blocks. Once he entered a block, the ground of this block would start to
sink and disappear in the next second. He could not stay at one block
for more than one second, nor could he move into a visited block. Can
the poor doggie survive? Please help him.
Input
The
input consists of multiple test cases. The first line of each test case
contains three integers N, M, and T (1 < N, M < 7; 0 < T <
50), which denote the sizes of the maze and the time at which the door
will open, respectively. The next N lines give the maze layout, with
each line containing M characters. A character is one of the following:
‘X‘: a block of wall, which the doggie cannot enter;
‘S‘: the start point of the doggie;
‘D‘: the Door; or
‘.‘: an empty block.
The input is terminated with three 0‘s. This test case is not to be processed.
Output
For each test case, print in one line "YES" if the doggie can survive, or "NO" otherwise.
Sample Input
4 4 5
S.X.
..X.
..XD
....
3 4 5
S.X.
..X.
...D
0 0 0
Sample Output
NO
YES
Author
ZHANG, Zheng
Source
Recommend
JGShining | We have carefully selected several similar problems for you: 1016 1242 1072 1026 1240
#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; }