机试算法讲解: 第46题 深度优先搜索之能否逃出魔掌

/*
DFS:主要用于求解有或者没有的问题,用栈。而BFS:用于求解最优问题,用队列。
问题:有一个N*M的迷宫,起点S,终点D,墙X和地面,'.'表示路,0秒时,我从S出发,每秒能走到4个与其相邻位置的任意一个,行走之后不能再次走入。问:是否存在一条路径使主人公刚好在
      T秒走到D
确定状态:(x,y,t),x与y是当前点坐标,t为从起点走到该点所需要的时间。
剪枝依据:起点坐标和的奇偶性和终点坐标的不同,但是经过偶数秒到达,不可能

输入:第一行3个整数,N(1<n,M<7,共有N行),M(M列),T(时间,0<T<50)。下面是N行,每行有M个字符,
输入:
4 4 5
S.X.
..X.
..XD
....
3 4 5
S.X.
..X.
...D
0 0 0
输出:
NO
YES

关键:
1 这里用深度优先搜索,就不需要用栈了,因为已经用了递归.
2 广度优先搜索需要使用访问标记,mark[][].而深度优先搜索由于要退回到上一层,因此不需要设置访问标记,而只需要设置成功标记
3 深度优先搜索的固定格式:maze[][] = 'X';DFS();maze[][]='.',递归前设置状态为不可用,递归后设置状态为可用,用于下一次退回使用
4 设置初始节点,要将起始状态设为墙,在进行深度搜索。这里没有使用标记mark的原因是'X'墙,'.'路已经起到了标记的作用,并且深度优先搜索设置已访问标记没有效果,
  向上回溯的时候,标记还需要设为可用
5 需要验证起始节点和结束节点以及时间之间的正确性,如果校验正确才进行递归,if((statBegin.x + statBegin.y)%2==((statEnd.x + statEnd.y)%2 + t%2)%2)
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stack>
#define N 7

using namespace std;

typedef struct Stat
{
	int x,y;//横纵坐标
	int t;//耗费时间
}Stat;

//stack<Stat> stackStat;//保存状态的堆栈

//bool mark[N][N];//剪枝标记
char maze[N][N];//保存迷宫元素
bool success;//设置是否找到的成功标记

//走下一个位置的数组
int goNext[][2] = 
{0,1,
-1,0,
1,0,
0,-1
};

//深度优先搜索
void DFS(int x,int y,int t,int n,int m,int tLimit)
{
	int i ;
	for(i = 0 ; i < 4 ; i ++)
	{
		int iXNext = x + goNext[i][0];
		int iYNext = y + goNext[i][1];

		//判定有无超过迷宫位置
		if(iXNext < 1 || iXNext > n || iYNext < 1 || iYNext > m)
		{
			continue;
		}
		//判定是否是墙
		if('X'==maze[iXNext][iYNext])
		{
			continue;
		}
		//判定是否到达终点,并且时间要符合
		if('D'==maze[iXNext][iYNext] && tLimit==(t + 1))
		{
			//易错,需要设置成功标记
			success = true;
			return;
		}
		maze[iXNext][iYNext] = 'X';
		//递归调用
		DFS(iXNext,iYNext,t+1,n,m,tLimit);
		//若其后续状态全部遍历完毕,返回上层状态,因为要搜索后续状态,因此再将墙改为普通状态
		maze[iXNext][iYNext] = '.';

		//易错,判断是否搜索成功
		if(true==success)
		{
			return;
		}
	}//for
	//如果一直遍历不到,则返回-1
	return;
}

int main(int argc,char* argv[])
{
	int n,m,t;
	int i,j;
	while(EOF!=scanf("%d %d %d",&n,&m,&t))
	{
		if(0==n && 0==m && 0==t)
		{
			break;
		}
		//获取输入信息,按行接受输入
		for(i = 1; i <= n;i++)
		{
			scanf("%s",maze[i]+1);//输入中不能用\n
		}
		//将起始点和结束点挑选出来
		Stat statBegin,statEnd;
		for(i = 1 ; i <= n ; i++)
		{
			for(j = 1 ; j <= m ; j++)
			{
				//如果找到起始点
				if('S'==maze[i][j])
				{
					statBegin.x = i;
					statBegin.y = j;
				}
				//如果找到结束点
				if('D'==maze[i][j])
				{
					statEnd.x = i;
					statEnd.y = j;
				}
			}
		}
		success = false;
		//如果校验正确才进行递归
		if((statBegin.x + statBegin.y)%2==((statEnd.x + statEnd.y)%2 + t%2)%2)
		{
			maze[statBegin.x][statBegin.y] = 'X';
			DFS(statBegin.x,statBegin.y,0,n,m,t);
		}
		puts(success==true ? "YES":"NO");
	}
	system("pause");
	getchar();
	return 0;
}

你可能感兴趣的:(DFS,深度优先搜索,机试算法)