关于地图遍历问题的总结

关于地图遍历问题的总结

先来看一道例题:

洛谷 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;
	}
}
原文地址:https://www.cnblogs.com/fusiwei/p/13220891.html