洛谷P1363幻象迷宫题解

题目信息

题目传送门

解题思路

在这里可怜喵星人一秒钟,然后我们开始讲题…
这道题明显是用搜索的 ,题目里的迷宫很容易让人想到dfs。
显然,我们可以把输入的一个迷宫变成九个迷宫,判断从起点(x, y)能否走到(x + n, y),(x - n, y),(x, y + m)或(x, y - m)。
但是大家会发现,这样的空间复杂度是很大哒,明显会MLE。
所以我们直接对迷宫去mod就好啦。
但是,如果走到过一个点又走到了这个点,那是可以走∞远的。
这里又出现了一大大大大大大堆问题。
想到这蒟蒻君也懵(´・ω・`)了…
参考网上大佬的题解后发现还有一个巧妙的方法…
我们记录取模的横纵坐标x, y,同时记录没有取模的坐标X, Y
当第一次走这个迷宫的时候,x, y和X, Y肯定是相等的。
所以只要走到的一个点的x, y和X, Y不相等,那这个点一定是被走了第二遍。

代码实现

建议先看一下蒟蒻君的dfs。
算法初探系列2——深度优先搜索之计算思维

#include <bits/stdc++.h>
using namespace std;
const int N = 1505;
const int dir_arr[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};   // 方向数组
int n, m;
int st_x, st_y; // 起点坐标
int vis[N][N][3];
bool flag, a[N][N];    // a[i][j]表示(i, j)是否可走,0表示可以
void dfs(int x, int y, int X, int Y) {
    if (flag) {
        return ;
    }
    // 具体含义见分析过程
    if (vis[x][y][0] && (vis[x][y][1] != X || vis[x][y][2] != Y)) {
        flag = true;
        return;
    }
    vis[x][y][0] = 1;
    vis[x][y][1] = X;
    vis[x][y][2] = Y;
    for (int i = 0; i < 4; ++i) {
        int nxt_x = (x + dir_arr[i][0] + n) % n;    // 不要忘记每轮的mod
        int nxt_y = (y + dir_arr[i][1] + m) % m;
        int nxt_X = X + dir_arr[i][0];
        int nxt_Y = Y + dir_arr[i][1];
        if (!a[nxt_x][nxt_y]) {
            if (vis[nxt_x][nxt_y][1] != nxt_X ||
                vis[nxt_x][nxt_y][2] != nxt_Y ||
                !vis[nxt_x][nxt_y][0]) {
                    dfs(nxt_x, nxt_y, nxt_X, nxt_Y);
            }
        }
    }
}
int main() {
    while (cin >> n >> m) {
        // 不要忘记每轮初始化
        flag = false;   // flag表示每轮答案
        memset(a, false, sizeof(a));
        memset(vis, false, sizeof(vis));
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < m; ++j) {
                char ch;
                cin >> ch;
                if (ch == '#') {    // 不能走到墙上
                    a[i][j] = 1;
                }
                if (ch == 'S') {    // 记录起点坐标
                    st_x = i;
                    st_y = j;
                }
            }
        }
        // 从起点开始尝试
        dfs(st_x, st_y, st_x, st_y);    // st_x和st_y取不取mod都是本身
        if (flag == true) {
            cout << "Yes\n";
        } else {
            cout << "No\n";
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蒟蒻一枚

谢谢鸭~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值