洛谷P1363幻象迷宫

问题描述

(喵星人LHX和WD同心协力击退了汪星人的入侵,不幸的是,汪星人撤退之前给它们制造了一片幻象迷宫。)

WD:呜呜,肿么办啊……

LHX:momo...我们一定能走出去的!

WD:嗯,+U+U!

描述 Description

幻象迷宫可以认为是无限大的,不过它由若干个N*M的矩阵重复组成。矩阵中有的地方是道路,用'.'表示;有的地方是墙,用'#'表示。LHX和WD所在的位置用'S'表示。也就是对于迷宫中的一个点(x,y),如果(x mod n,y mod m)是'.'或者'S',那么这个地方是道路;如果(x mod n,y mod m)是'#',那么这个地方是墙。LHX和WD可以向上下左右四个方向移动,当然不能移动到墙上。

请你告诉LHX和WD,它们能否走出幻象迷宫(如果它们能走到距离起点无限远处,就认为能走出去)。如果不能的话,LHX就只好启动城堡的毁灭程序了……当然不到万不得已,他不想这么做。。。


输入格式:

输入包含多组数据,以EOF结尾。

每组数据的第一行是两个整数N、M。

接下来是一个N*M的字符矩阵,表示迷宫里(0,0)到(n-1,m-1)这个矩阵单元。


输出格式:

对于每组数据,输出一个字符串,Yes或者No。


输入样例:

输入:
5 4
##.#
##S#
#..#
#.##
#..#
5 4
##.#
##S#
#..#
..#.
#.##

输出:

Yes
No

题目分析: 

这是一道典型的dfs问题——迷宫问题。但本蒟蒻之前所看到的迷宫问题是迷宫大小固定的,这道题目不同的是迷宫由若干个N*M的矩阵重复组成。所以在套用模板之前,首先需要想清楚的是如何判断递归出口

思考了一段时间后依旧没有思绪,于是参考了题解。题解中给出的思路是这样子的:

定义四个变量,记录取模后的横纵坐标x,y ,以及没有取模的tx、ty。当第一次走这个迷宫的时候,x,y和tx、ty肯定是分别相等的,所以只要走到的一个点的x、y和tx、ty不相等(x≠tx || y≠ty),那这个点一定是被走了第二遍。

因此我们的递归出口就可以写成:

if(这个点已经标记过 && (该点横坐标不等于上次递归的横坐标 || 该点纵坐标不等于上次递归的纵坐标)){
则说明迷宫有路走出去,答案返回1;
return;
}

我们将上述判断条件用一个三维数组表示,第一维记录有无被访问,第二维记录被访问时横坐标,第三维纵坐标。

int book[1501][1501][3];

每次进入dfs递归调用都需要先判断是否满足出口条件,若不满足,则更新该三维数组。

book[x][y][1] = tx;//记录当前位置
book[x][y][2] = ty;
book[x][y][0] = 1;//进行位置标记

然后根据上下左右四个方向走,不断碰壁。这里又有一个关键点来了,如何走出当下的n*m的迷宫矩阵走到另一个n*m的迷宫矩阵,从而判断这个无限的迷大宫有出路呢?这里就需要更新我们的x,y了。那么如何更新x,y呢?前面我们就有提到,用取模后的横纵坐标x,y ,以及没有取模的tx、ty是否相等来判断。(题目也有提示我们用取模的方式来解决)那么具体代码如下:

//step[k]表示向上、下、左、右四个方向走
int xx = (x + step[k][0] + n) % n;
int yy = (y + step[k][1] + m) % m;
int txx = tx + step[k][0];
int tyy = ty + step[k][1];

这样,这道题目最困难的点我们就解决了。注意!由于迷宫可以输入多组数据,所以别忘了每次进行下一组数据的计算时先把判断矩阵和迷宫矩阵重置以下。以下是完整代码:

完整代码:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int book[1501][1501][3];
int a[1501][1501];
int n, m;
int startx, starty;
int ans;
char q;
int step[4][2] = {{0,1},{0,-1},{1,0},{-1,0}};

void dfs(int x, int y, int tx, int ty){
    if(ans) return;
    if(book[x][y][0] && (book[x][y][1] != tx || book[x][y][2]!= ty)){//递归出口
        ans = 1;
        return;
    }
    book[x][y][1] = tx;//进行标记
    book[x][y][2] = ty;
    book[x][y][0] = 1;
    for(int k = 0; k <= 3; k++){
        int xx = (x + step[k][0] + n) % n;
        int yy = (y + step[k][1] + m) % m;
        int txx = tx + step[k][0];
        int tyy = ty + step[k][1];
        if(!a[xx][yy]){
            if(!book[xx][yy][0] || book[xx][yy][1] != txx || book[xx][yy][2] != tyy){
                dfs(xx,yy,txx,tyy);
            }
        } 
    }
}

int main(){
    while(scanf("%d%d",&n,&m)!=EOF){
        ans = 0;
        memset(a, 0, sizeof(a));//重置数组
        memset(book, 0, sizeof(book));
        for(int i = 0; i < n; i++){
            for(int j = 0; j < m; j++){
                //scanf("%c",&q); 在这里使用scanf会出现输入问题,具体原因还请各位小伙伴自行查找
                cin >> q;
                if(q == '#') a[i][j] = 1;
                if(q == 'S'){
                    startx = i;
                    starty = j;
                }
            }
        }
        dfs(startx,starty,startx, starty);
        if(ans) printf("Yes\n");
        else printf("No\n");
    }
    
}

以上就是这道题目的一些学习记录啦~如果有帮到你,能不能点个赞支持一下哇😝😝

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值