一、题目描述
帮助doggie走出迷宫。迷宫由‘S’(起点)、‘X’(墙,不可通过)、‘D’(终点)、和‘.’(可走格子)组成。给定时间T,doggie每秒走一格,要求不可重复走,且刚好在T秒内走到终点D。如果有这样的路径,输出“YES”,否则“NO”。
二、样例
输入:
4 4 5 S.X. ..X. ..XD .... 3 4 5 S.X. ..X. ...D 0 0 0
NO YES
三、分析
深搜DFS问题。从起点开始,doggie每秒有4种走法,即上、下、左、右,下一秒又在上一次的基础上有4种选择。我们要做的就是对这所有的情况剪枝。
1、边界。遇到迷宫的边缘,或者代表无法通过的X,不再继续搜索;
2、重复。已经走过的区域不再重复搜索;
3、奇偶剪枝。这个不太容易想到。可以这样考虑:先计算起点到终点的最短距离d,由于有墙的存在,给的时间走过的步数T减去最短距离d,也就是需要绕路走的步数 t = T - d。这个绕路步数必须是偶数,否则无法到达终点。
4、时间。如果给的时间超过可走的步数+1,则一定无法到达。具体可以看这个样例:
2 4 7 S..D ....
可走块数sum为6,时间T为7,刚好走完所有块到达终点。若sum < T - 1,一定无法到达。
另外要注意的就是递归,要小心跳出条件和恢复上一层。
四、代码
/**********************************************
*时间:2018-01-29
*内容:深搜+剪枝
*技巧:搜索的时候剪枝一定要考虑完全,能剪的都
剪掉,否则容易超时;递归思路要清晰
***********************************************/
#include<iostream>
#include<cstring>
#include<cmath>
#include <stdlib.h>
using namespace std;
int dx[4]={1,0,-1,0},dy[4]={0,-1,0,1};
int n,m,t,sum; //记录迷宫大小和时间,可走的块数
int sx,sy,ex,ey; //记录起点和终点坐标
char maze[7][7];
bool record[7][7];//记录迷宫是否被走过
bool flag = false;
void dfsMaze(int nx,int ny,int layer)
{
if(layer == t ){ //跳出条件
if(maze[nx][ny] == 'D' ) flag = true;
return;
}
for(int i = 0; i < 4; ++ i){
//排除边界情况
if(nx + dx[i] < 0 || nx + dx[i] == n || ny + dy[i] < 0 || ny + dy[i] == m) continue;
//对墙 和 已经走过的部分 剪枝
if(maze[nx + dx[i]][ny + dy[i]] == 'X' || !record[nx + dx[i]][ny + dy[i]]) continue;
//如果在时间到之前就走到D,也无法走出迷宫。剪枝
if(layer < t - 1 && maze[nx + dx[i]][ny + dy[i]] == 'D') continue;
record[nx+dx[i]][ny+dy[i]] = false; //记录该块已经走过
nx = nx + dx[i];
ny = ny + dy[i];
//进入下一层搜索
dfsMaze(nx,ny,++ layer);
//恢复
if(flag) return; //只要找到一条路线,就不再寻找
record[nx][ny] = true;
layer --;
nx = nx - dx[i];
ny = ny - dy[i];
}
}
int main()
{
while(true){//读入数据
cin>>n>>m>>t;
if(n==0) break;
memset(record,true,sizeof(record));
flag = false;
sum = 0;
for(int i = 0;i < n; ++ i){
for(int j = 0;j < m; ++ j){
cin >> maze[i][j];
if(maze[i][j] == '.') sum++;
//记录终点和起点位置
if(maze[i][j] == 'D'){ex = i;ey = j;}
if(maze[i][j] == 'S'){sx = i;sy = j;record[i][j] = false;}
}
}
//如果可走的步数小于时间-1,或者需要绕弯走的步数是奇数,不可到达
if(sum < t - 1 || (t - (abs(sx - ex) + abs(sy - ey))) % 2)cout<< "NO" <<endl;
else{
dfsMaze(sx,sy,0);
if(flag) cout << "YES" << endl;
else cout << "NO" << endl;
}
}
}