关于地图遍历问题的总结
关于地图遍历问题的总结
先来看一道例题:
洛谷 AT1350 深さ優先探索
题意翻译
高桥先生住的小区是长方形的,被划分成一个个格子。高桥先生想从家里去鱼店,高桥先生每次可以走到他前后左右四个格子中的其中一个,但不能斜着走,也不能走出小区。
现在给出地图:
s
:代表高桥先生的家
g
:代表鱼店
.
:代表道路
#
:代表墙壁
高桥先生不能穿过墙壁。
输入:第一行输入n(1<=n<=500),m(1<=m<=500)代表小区的长和宽,接下来n行每行m个字符,描述小区中的每个格子。
输出:如果高桥先生能到达鱼店,输出"Yes",否则输出"No"。
地图遍历问题
这种需要按要求从一个点出发“走迷宫”的题,本蒟蒻给它起了个名字叫做地图遍历问题。
应该是非常基础的深搜例题,只是在此做个总结,顺便复习一下深搜。
首先是思路:
深搜的定义大家应该都有所了解。但是这种定义方式是基于树和图的深度优先遍历的,比较容易被大家理解。所以应该有好多小伙伴都是像本蒟蒻一样蒙圈:这种题无图无树,和深搜有关系么?
这就需要一个思维转换:构建搜索树。
所谓搜索树,就是把乍一看没法用深搜解决的问题抽象成一棵树,不是说深搜是对树和图的深度优先遍历么?那我把这个问题变成一个图,不就解决了么?
那好,我们开始抽象:
一张地图,对于每一个点(就是矩阵的每一个坐标),它有四个选择可走:上下左右。那么,我们可以将其抽象成一个每个节点有四个子节点的图。(当然,边界节点和墙都是除外的)
有了这个思路,就可以进行搜索的代码模拟了。
代码思路
首先是“指南针”——方向数组,这个数组帮助我们更改点的坐标,使得搜索有序进行。
int dx[]={0,0,0,-1,1};
int dy[]={0,1,-1,0,0};
然后是正常的搜索,搜索的函数可以归纳成这个模板:
void dfs(int x,int y)
{
if(target)
return answer;
for(int i=1;i<=4;i++)
{
int xx=x+dx[i];
int yy=y+dy[i];
if(condition)
continue;
dfs(xx,yy);
}
}
其中target是目标条件,answer是答案或者处理,condition是继续搜索的条件,也可以理解为剪枝。
那么,这个继续搜索的条件也有一个一般套路,就是我们需要让当前的\((xx,yy)\)点不越界,这个条件是所有“地图遍历”问题都必须要有的,其他的限制条件依题意再规范。
那么,以上的例题就可以得到求解,代码是这样的:
#include<cstdio>
#include<iostream>
using namespace std;
const int maxn=510;
int n,m;
char map[maxn][maxn];
bool v[maxn][maxn];
int dx[]={0,0,0,-1,1};
int dy[]={0,1,-1,0,0};
int a,b,c,d;
void dfs(int x,int y)
{
v[x][y]=1;
for(int i=1;i<=4;i++)
{
int xx=x+dx[i];
int yy=y+dy[i];
if(xx<1 || xx>n || yy<1 || yy>m || map[xx][yy]=='#' || v[xx][yy])
continue;
dfs(xx,yy);
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
cin>>map[i][j];
if(map[i][j]=='s')
a=i,b=j;
if(map[i][j]=='g')
c=i,d=j;
}
dfs(a,b);
if(v[c][d])
{
printf("Yes");
return 0;
}
else
{
printf("No");
return 0;
}
}