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
代码如下:
#include <iostream> using namespace std; const int dx[4]= {1,-1,0,0}; const int dy[4]= {0,0,1,-1}; char str[7][7]; int N,M,T,k,n; bool dir(int x,int y) { return x>=0&&y>=0&&x<N&&y<M; //判断是否在区域内 } void findpath(int x,int y) { int nx,ny,i; char tmp=str[x][y]; //先将原来的位置信息记录 str[x][y]='X'; //将走过的位置更改为X; k++; for (i=0; i<4; i++) //向四个方向搜索 { nx=x+dx[i]; ny=y+dy[i]; if (dir(nx,ny)&&str[nx][ny]!='X') //如果在区域内且该位置不为X; { if (str[nx][ny]=='D') //如果到达的位置是点D { if (k+1==T) //此时k还没有加1,比较k+1与预计的步数T { n=1; //如果相等,则n改为1; break; } } else { findpath(nx,ny); //递归 if (n==1) //如果n为1,跳出循环。 break; } } } str[x][y]=tmp; //回退 k--; //回退 } int main() { int i,j; int x,y,tx,ty; while (cin>>N>>M>>T) { n=0; if (N==0||M==0||T==0) break; for (i=0; i<N; i++) { for (j=0; j<M; j++) { cin>>str[i][j]; if (str[i][j]=='S') //记录起始位置S的信息 { x=i; y=j; } else if (str[i][j]=='D') //记录末尾位置D的信息 { tx=i; ty=j; } } } if (((T%2==0) && ((x+y)%2==(tx+ty)%2)) || ((T%2==1) && ((x+y)%2!=(tx+ty)%2))) //深度搜索黑白棋 { k=-1; findpath(x,y); } if (n==0) //如果n为0,则说明不能 cout<<"NO"<<endl; else //否则能 cout<<"YES"<<endl; } return 0; }
解题思路:
题目大意是给定一个区域,区域内有S和D两个点,问S到D能否用给定的步数到达(多或少都不行)(X是不能通过的位置)。
思路还是递归回溯法,不过这里又用到了一种叫深度搜索黑白棋的方法,用来排除注定走不到的“死路”,而且需要注意的是,由于可能有些路径不能在给定的步数到达,然后需要返回,需要把计数的k值回归到在某一位置开始搜索时的步数,所以在findpath的函数中需要先记录原先的位置,在搜索不成功后又返回到原先的位置。
深度搜索:在深度优先搜索的过程当中,往往有很多走不通的“死路”。假如我们把这些“死路”排除在外,不是可以节省很多的时间吗?打一个比方,前面有一个路径,别人已经提示:“这是死路,肯定不通”,而你的程序仍然很“执着”地要继续朝这个方向走,走到头来才发现,别人的提示是正确的。这样,浪费了很多的时间。针对这种情况,我们可以把“死路”给标记一下不走,就可以得到更高的搜索效率。
深度搜索黑白棋:在国际象棋盘中,棋格是黑白相间的,如果步数T是偶数的话,末尾的颜色和起始的颜色是相同的;如果步数T是奇数,则首尾颜色是不同的。如果是和本题类似的题目用到这种方法,可以排除很多死路。