迷宫寻路-搜索
Problem:558 Time Limit:1000ms Memory Limit:65536K
Description
AC小公主很喜欢设计迷宫,她设计的迷宫只有两个口,一个入口,一个出口。但小公主有时候很调皮,她会让挑战者走不出迷宫。现在给你AC小公主的迷宫请你判断挑战者能否成功从出口走出迷宫,迷宫包证边界为障碍物,只有两个不同的入口。
“#”代表障碍物,“*”代表可走的路。
Input
输入有多组,每组输入两个正整数n,m( 2 < n < m < 1000)。
接下来n行,每行有m个字符。
Output
每组测试实例,若挑战者能走出迷宫输出”YES”,否则输出“NO”。
Sample Input
3 3
#*#
#*#
#*#
3 3
#*#
###
#*#
Sample Output
YES
NO
错误
看到这道题的第一眼,我就想到了用深搜的方法来解决这道题。(其实,广搜也可以。)我第一想法是像最典型的深搜一样,找到一个“*”,然后分别从四个方向(上、下、左、右)一遍一遍地调用深搜函数,直到每个点都走了一次为止,最后检查这个二维数组还有没有“*”存在。如果有那就是走不出迷宫。后来我发现这样想是错的!!!大错特错!!!因为,这样想有一个前提是在这个迷宫里有且只有一条通路,且没有一个多余的点,且忽略了要从唯一一个入口进入。
正确思路
那么,这道题的正确思路是什么呢?通过题目我们可以知道:这个迷宫只有两个口,一个入口,一个出口。这点很重要哦!不要小瞧它。我们要做的第一步就是找到入口和出口,并把这两个点标记一下。这里我是采用遍历的方式,当一个点处在二维数组的边界(也就是横坐标为1或n,纵坐标为1或m时,这里我都是从1开始输入的),并且为“*”时,那它就是入口/出口,我分别用一个int类型的一维数组来记录下这个点的横、纵坐标。由题意知,我们一定会找到两个点,那么我们就令第一个找到的点为入口,第二个为出口。然后,我们从第一个点开始深搜。深搜的过程是,我们已经直到此时的点为“*”,那我们就马上把这个点变为“#”,代表我们走过了,然后往它的四个方向走,如果这个点满足在这个数组,并且为“*”的条件的话,我们就继续调用这个函数。就这样深搜结束后,因为我们之前标记过出口的坐标了,现在我们只要检查,经过这一次深搜后,出口点是不是由“*”变成了“#”。如果出口点已经变成了“#”,那就证明有这样一条路径,可以从入口走到出口;反之,则没有。
代码
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
char a[1005][1005];
int dx[4]={0,1,0,-1};
int dy[4]={1,0,-1,0};
int flag;
int strx[5],stry[5];
int n,m;
void dfs(int x,int y)
{
a[x][y]='#';
int x1,y1;
for(int i=0;i<4;i++)
{
x1=x+dx[i];
y1=y+dy[i];
if(x1>=1&&x1<=n&&y1>=1&&y1<=m&&a[x1][y1]=='*')
{
dfs(x1,y1);
}
}
}
int main()
{
while(cin>>n>>m)
{
flag=0;
int p=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
cin>>a[i][j];
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if((i==1||i==n||j==1||j==m)&&a[i][j]=='*')//找到出入口
{
strx[++p]=i;
stry[p]=j;
}
}
}
dfs(strx[1],stry[1]);
if(a[strx[2]][stry[2]]=='#') flag=1;
if(flag==1) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
//cout << "Hello world!" << endl;
return 0;
}