关于dfs+剪枝第一篇:hdu1010
最近进入了dfs关于剪枝方面的学习,遇到的第一道题就是hdu的1010。一道很基础的剪枝。。可我不幸地wa了很多次(待会再解释wa的原因吧QAQ),首先我们来看一下题目。
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.
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.
'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.
翻译请自行翻译或是抱住谷歌大娘的大腿
题目很明显,是一道经典的迷宫问题,值得一提的是,这个迷宫并不是要求你在规定的时间内到达出口,而是要在指定的时间点到达出口。有什么思路呢?
在写出基本的迷宫后,我们可以开始剪枝这一项伟大工程了。
首先我们考虑,在这样一个矩阵里,如果指定的时间大于走遍所有能走的地方的时间或是小于出发点到出口的最短路径,那么这只可怜的狗狗一定会被困在迷宫里了。
其中,t为指定时间,sum为墙的个数。
if((t>h*l-sum-1)||(t<abs(xz-x0)+abs(yz-y0)))printf("NO\n");
其次,我们考虑在一个矩阵中,如果到达出口需要奇数步,而我们到达出口会走偶数步时,狗狗出不去;同理,若到达出口需要偶数步,而我们会走奇数步时,狗狗同样出不去。
用一个1和0组成的矩阵作为例子:
1 0 1 0 1 0
0 1 0 1 0 1
1 0 1 0 1 0
0 1 0 1 0 1
从图中便可以清楚地看到,奇数步所能走到的,偶数步必然走不到。
那么我们通过判断起点的奇偶性和终点的奇偶性,再将它们加和与指定时间的奇偶性进行比较,便可以完成第二个剪枝:奇偶剪枝。
else if(((x0+y0)%2+(xz+yz)%2)%2!=t%2)printf("NO\n");
接下来介绍几个技巧:
void dfs(int p,int q,int num){ int i,x,y; if(tmp)return ;//如果可以到达,便不再dfs,一直退层,直到退出dfs; for(i = 0 ; i < 4 ; ++i){ x=p+u[i];y=q+r[i]; if(x>=1&&x<=h&&y>=1&&y<=l&&a[x][y]){ a[x][y]=false; if(x==xz&&y==yz&&num==t){ tmp=1; return ; } else if(num<t)dfs(x,y,num+1); a[x][y]=true; } } }
以上便是1010这道题的所有注意点了,然后贴出代码~
#include<cstdio> #include<cstring> #include<stdlib.h> int u[10]={1,-1,0,0},r[10]={0,0,1,-1}; bool a[20][20]; int h,l,xz,yz,tmp,t; void dfs(int p,int q,int num){ int i,x,y; if(tmp)return ; for(i = 0 ; i < 4 ; ++i){ x=p+u[i];y=q+r[i]; if(x>=1&&x<=h&&y>=1&&y<=l&&a[x][y]){ a[x][y]=false; if(x==xz&&y==yz&&num==t){ tmp=1; return ; } else if(num<t)dfs(x,y,num+1); a[x][y]=true; } } } int main(){ int x0,y0; char w[10]; while(scanf("%d%d%d",&h,&l,&t)!=EOF){ int sum=0; if(h==0&l==0&t==0)return 0; memset(a,1,sizeof(a)); for(int i = 1 ; i <= h ; ++i) { scanf("%s",w+1); for(int j = 1 ; j <= l ; ++j){ if(w[j]=='X'){ a[i][j]=false; ++sum; } else if(w[j]=='S'){ x0=i; y0=j; a[i][j]=false; } else if(w[j]=='D'){ xz=i; yz=j; } } } if((t>h*l-sum-1)||(t<abs(xz-x0)+abs(yz-y0)))printf("NO\n"); else if(((x0+y0)%2+(xz+yz)%2)%2!=t%2)printf("NO\n"); else { dfs(x0,y0,1); if(tmp==1)printf("YES\n"); else printf("NO\n"); } tmp=0; } }
至于我wa的原因。。。是把t当成sum一直在用(尴尬)。。。更可怕的是,样例数据竟然过了...
犯这样的错误也给我自己留下深刻的教训,以后写代码要认真写,以免再犯这样的错误,大家也是一样。
以上便是对1010这道题的所有分析,若有讲的漏洞或是错误请大家纠正出来,希望一次做的比一次好~bye~~