传送门:牛客
题目描述:
小明现在在玩一个游戏,游戏来到了教学关卡,迷宫是一个N*M的矩阵。
小明的起点在地图中用“S”来表示,终点用“E”来表示,障碍物用“#”来表示,空地用“.”来表示。
障碍物不能通过。小明如果现在在点(x,y)处,那么下一步只能走到相邻的四个格子中的某一个:(x+1,y),(x-1,y),(x,y+1),(x,y-1);
小明想要知道,现在他能否从起点走到终点。
输入:
3 3
S..
..E
...
3 3
S##
###
##E
输出:
Yes
No
这是一道经典的搜索入门题,对于这道题,我们既可以使用DFS
,当然也可以使用BFS
,这在本题中都没有任何问题(也不会出现超时的情况),如果不会DFS或者BFS的模板的话,请自行百度学习
对于此题:我们很容易的打出一下代码
void dfs(int x,int y) {
if(x==zdx&&y==zdy) {
flag=1;return;
}
for(int i=0;i<=3;i++) {
int nx=x+dx[i],ny=y+dy[i];
if(nx>=1&&nx<=n&&ny>=1&&ny<=m&&vis[nx][ny]==0) {
vis[nx][ny]=1;
dfs(nx,ny);
vis[nx][ny]=0;//回溯
}
}
return ;
}
但是交上去会发现竟然超时了两个点,这是为什么呢.你为此感到疑惑,然后翻了一下题解,发现题解中使用DFS的代码都没有vis数组的维护,然后你感到疑惑(或者恍然大悟),假设你已经恍然大悟,那么就不需要继续看这篇博客了,但是如果没有,请往下看(因为大部分博客&题解都没有解释这一步操作)
这是因为当我们搜索到一个点时,假设我们继续dfs下去并且回溯到这个位置,那就意味着刚才搜索过的点要么已经被记录到正确答案了,或者这个点是走不通的那么此时我们显然就不需要继续经过这个点了,这个经过是指即使从其他路径到该点,那么之后的情况也会和此时的一样,所以就没有必要继续的重复我们之前的操作了,这算是一个小小的优化吧
具体的代码部分(DFS):
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f
#define root 1,n,1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
inline ll read() {
ll x=0,w=1;char ch=getchar();
for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
return x*w;
}
#define maxn 1000000
#define ll_maxn 0x3f3f3f3f3f3f3f3f
const double eps=1e-8;
int n,m;
char mp[1000][1000];
int vis[1000][1000];
int dx[4]={1,0,-1,0};
int dy[4]={0,-1,0,1};
int qdx,qdy,zdx,zdy;
int flag=0;
void dfs(int x,int y) {
if(x==zdx&&y==zdy) {
flag=1;return;
}
for(int i=0;i<=3;i++) {
int nx=x+dx[i],ny=y+dy[i];
if(nx>=1&&nx<=n&&ny>=1&&ny<=m&&vis[nx][ny]==0) {
vis[nx][ny]=1;
dfs(nx,ny);
}
}
return ;
}
int main() {
while(scanf("%d%d",&n,&m)!=EOF) {
memset(mp,'\0',sizeof(mp));
memset(vis,0,sizeof(vis));
flag=0;
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
cin>>mp[i][j];
if(mp[i][j]=='S') {
qdx=i;qdy=j;
vis[i][j]=1;
}
if(mp[i][j]=='E') {
zdx=i;zdy=j;
}
if(mp[i][j]=='#') {
vis[i][j]=1;
}
}
}
dfs(qdx,qdy);
if(flag) printf("Yes\n");
else printf("No\n");
}
return 0;
}
众所周知,DFS是深度优先搜索,这就意味着我们在递归的时候是一次性的递归到底部的,但是BFS则是广度优先搜索,这就意味着我们在递归的时候是逐渐的往外扩展的,两者各有优劣吧,根据情况妥善选择(当然此题都可以AC)
BFS主要依赖于队列的先进先出原则,BFS不需要回溯
具体的代码部分:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f
#define root 1,n,1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
inline ll read() {
ll x=0,w=1;char ch=getchar();
for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
return x*w;
}
#define maxn 1000000
#define ll_maxn 0x3f3f3f3f3f3f3f3f
const double eps=1e-8;
char mp[1000][1000];
int vis[1000][1000];
int qdx,qdy,zdx,zdy;
int flag=0;
struct Node{
int x,y;
};
queue<Node>q;
int dx[4]={1,0,-1,0};
int dy[4]={0,-1,0,1};
int n,m;
void Bfs(int x,int y) {
if(q.size()) q.pop();
q.push({x,y});
while(!q.empty()) {
for(int i=0;i<=3;i++) {
int nx=q.front().x+dx[i],ny=q.front().y+dy[i];
if(nx>=1&&nx<=n&&ny>=1&&ny<=m&&vis[nx][ny]==0&&flag==0) {
vis[nx][ny]=1;
if(nx==zdx&&ny==zdy) flag=1;
q.push({nx,ny});
}
}
q.pop();
}
return;
}
int main() {
while(scanf("%d%d",&n,&m)!=EOF) {
flag=0;
memset(vis,0,sizeof(vis));memset(mp,'\0',sizeof(mp));
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
cin>>mp[i][j];
if(mp[i][j]=='S') {
qdx=i;qdy=j;
vis[i][j]=1;
}else if(mp[i][j]=='#') {
vis[i][j]=1;
}else if(mp[i][j]=='E') {
zdx=i,zdy=j;
}
}
}
Bfs(qdx,qdy);
if(flag==1) printf("Yes\n");
else printf("No\n");
}
return 0;
}