AcWing 1112. 迷宫

题目链接

题意

给一个n*n的二维矩阵,矩阵中只有’.‘和’#‘这两种状态,’.‘表示可以走,’#‘是障碍,给出起点和终点,只能上下左右走(四连通),还需要注意两点:1.起点有可能就是终点 2.起点和终点都有可能是’#’

分析

题目是经典的dfs题,就判断是否到了终点没,没到终点就一直尝试往四个方向搜

解决方案

1.初始化数据,输入矩阵大小、初始化状态数组、输入起点终点坐标
2.先判断起点和终点是不是’#’,然后再判断是否为同一坐标
3.执行dfs,一直搜,如果有就标记答案变量,没有就不做标记

踩坑

我第一次做这题就TLE,不知道为什么,后来才知道原来这题不需要回溯的。。。

一开始的写法:

st[a][b] = 1;
dfs(a, b);
st[a][b] = 0;  

更改后的写法:

st[a][b] = 1;
dfs(a, b);

这种类型的搜索是不用回溯的,因为多种状态可以同时更新,搜索数是这样的

AcWing 1112. 迷宫_第1张图片
而需要回溯的搜索树是这样的

AcWing 1112. 迷宫_第2张图片
以上的搜索树对应的是Leetcode79题这种类型的搜索树,每当找到符合条件的字符就更新状态,遇到不符合条件的字符就回溯到之前的节点,并恢复现场

代码

#include 
#include 

using namespace std;

const int N = 105;

//n为迷宫的大小,x1和y1分别为起点所在行索引和所在列索引,x2和y2则对应终点
//ans为标记变量,一旦找到终点即标记ans为1
int n, x1, y1, x2, y2, ans;
//以下为偏移向量,对应上右下左
int dx[] = {
     -1,0,1,0}, dy[] = {
     0,1,0,-1};;

char g[N][N];  //g为存储迷宫矩阵
bool st[N][N]; //st里的值表示点有没有被标记过

void dfs(int x, int y) {
     
    //找到终点,标记一下,并返回
    if (x == x2 && y == y2) {
     
        ans = 1;
        return;
    }
    //往四个方向尝试遍历
    for (int i = 0; i < 4; i++) {
     
        int a = x + dx[i], b = y + dy[i];
        //索引要合法,点不能被标记过,也不能是障碍
        if (a >= 0 && a < n && b >= 0 && b < n && !st[a][b] && g[a][b] == '.') {
     
            st[a][b] = 1;
            dfs(a, b);
        } 
    }
}

int main() {
     
    int t;   //t为测试案例的组数
    cin >> t;
    while (t--) {
     
        cin >> n;
        ans = 0;
        memset(st, 0, sizeof st);
        for (int i = 0; i < n; i++) scanf("%s", g[i]);
        scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
        
        //以下if语句判断的是起点和终点有没有可能是障碍
        if (g[x1][y1] == '#' || g[x2][y2] == '#') {
     
            puts("NO");
            continue;
        }
        
        //以下if语句判断的是起点是否就是终点
        if (x1 == x2 && y1 == y2) {
     
            puts("YES");
            continue;
        }
        
        st[x1][y1] = 1;
        dfs(x1, y1);
        if (ans == 1) puts("YES");
        else puts("NO");
    }
}

你可能感兴趣的:(搜索,dfs,算法)