DFS(深搜算法)问题2之迷宫问题—杭电OJ 1010

读者可先学习深搜解决全排列问题

bfs和dfs的区别

  • bfs更适合解决带有“最少”,“最短”字样的题
  • dfs更适合解决带有“刚刚”,“刚好”字样的题

在练习迷宫问题之前,先介绍一下奇偶性剪枝:

  • 若地图上某点的行号加列号为奇数,则将其定义为奇点
  • 若地图上某点的行号加列号为偶数,则将其定义为偶点
  • 行与列从(0,0)开始
  • 奇点用1表示
  • 偶点用0表示

通过以上定义可以把一个地图表示为下图(01相间):
在这里插入图片描述
不难发现:

在每一步消耗一个单位时间的情况下:

  • 0的下一步只能走向1
  • 1的下一步只能走向0
  • 从0走向1需要的步数(时间)一定是奇数
  • 从1走向0需要的步数(时间)一定是奇数
  • 从0走向0需要的步数(时间)一定是偶数
  • 从1走向1需要的步数(时间)一定是偶数

通过这个性质可以对一些问题进行剪枝,称奇偶性剪枝。

迷宫问题原题链接

题目大意

小狗在一个古老的迷宫中发现了一根骨头,这使他非常着迷。 但是,当他捡起它时,迷宫开始摇晃,小狗可以感觉到地面下沉。 他意识到骨头是一个陷阱,他拼命试图摆脱这个迷宫。
迷宫是一个矩形,大小为N×M。迷宫中有一扇门。 刚开始时,门是关闭的,它将在第T秒打开一小段时间(少于1秒)。 因此,小狗必须在第T秒精确到达门。 每秒钟,他可以从一个块移动到上,下,左和右相邻的块之一。 一旦他进入一个块,该块的地面将开始下沉并在下一秒消失。 他不能在一个块停留超过一秒钟,也不能移动到一个已经去过的块。 可怜的小狗可以生存吗? 请帮助他。

输入

输入包含多个测试用例。 每个测试用例的第一行包含三个整数N,M和T(1 <N,M <7; 0 <T <50),分别表示迷宫的大小和门打开的时间。 。 接下来的N行给出迷宫的布局,每行包含M个字符。 字符是以下之一:
“ X”:狗无法进入的一堵墙
‘S’:小狗的起点
‘D’:门
‘.’:一个空块
输入以三个0终止。 该测试用例将不被处理。

输出

对于每个测试用例,如果小狗可以存活,则在一行中打印“是”,否则打印为“否”。

样例输入

4 4 5
S.X.
…X.
…XD

3 4 5
S.X.
…X.
…D
0 0 0

样例输出

NO
YES

本题中遇到的剪枝

  • 如果所有的迷宫块 - 障碍物的数量 < 时间,说明小狗会提前到达门前,狗必死无疑。
  • 两点间的最短距离为abs(x1 - x2) + abs(y1 - y2)
  • temp % 2为奇偶性剪枝,以下图为例。 若此时小狗走到了黄色的点上,并且此时剩余6个单位时间逃生的门才会打开。而终点与目前所在点的距离只有1个单位,由si到达di也只需要一个单位时间。因此,temp = 6 - 1 = 5。此时到达了door还剩余5个时间单位。又因为失败的有两个点 1. 是剩余时间不够 2. 是到达了door还有剩余时间。假设到了点door,还剩下3个时间,则剩下三个时间没法从Door,到其他点,再到达door,只有偶数时间可以。

在这里插入图片描述

AC代码及详细注释

#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

int n,m,t;//n,m分别表示矩阵的行和列,t表示开门的时间
int wall;//障碍物的数量(有利于剪枝)
int si,sj;//小狗的开始位置(start)
int di,dj;//门/终点的位置(door)
int escape;//表示小狗是否可以逃脱迷宫
char map[10][10];//字符数组,用来存储迷宫
int direct[4][2] = {{-1,0},{1,0},{0,-1},{0,1}};//方向数组,用来实现移动方向,分别表示上下左右

void dfs(int si,int sj,int time)
{
    if (si > n || sj > m || si <= 0 || sj <= 0) return;//行不大于n,列不大于m,行和列不小于等于0
    if (si == di && sj == dj && time == t) escape = 1;//到达门前且时间刚好,门刚好打开,此时小狗可以逃出
    if (escape) return;//逃出迷宫
    
    int temp;
    temp = (t - time) - abs(si - di) - abs(sj - dj);//t - time表示当前剩余时间,每走一步表示一个单位时间
    if (temp < 0 || temp % 2) return;//temp < 0表示当前的剩余时间结束前不能走到门口
    
    for (int i = 0;i < 4;i++)//4次循环表示四个方向
    {
        if (map[si + direct[i][0]][sj + direct[i][1]] != 'X' )//如果某个方向不是障碍物
        {
            map[si + direct[i][0]][sj + direct[i][1]] = 'X';//当前位置开始下陷
            dfs(si + direct[i][0],sj + direct[i][1],time + 1);//向这个方向尝试
            map[si + direct[i][0]][sj + direct[i][1]] = '.';//回溯
        }
    }
    return;
}

int main()
{
    while (cin >> n >> m >> t && (n + m + t) )
    {
        wall = 0;
        for (int i = 1;i <= n;i++)
        {
            for (int j = 1;j <= m;j++)
            {
                cin >> map[i][j];//读入地图
                if (map[i][j] == 'S')//找到小狗的开始位置 
                {
                    si = i;
                    sj = j;
                }else if (map[i][j] == 'D')
                {
                    di = i;//找到门的位置
                    dj = j;
                }else if (map[i][j] == 'X')
                {
                    wall += 1;//墙/障碍的数量
                }
            }
        }
        
        if (n * m - wall < t) //剪枝
        {
            cout << "NO" << endl;
            continue;
        }
        
        escape = 0;//escape必须初始化
        map[si][sj] = 'X';//当前位置开始下陷
        dfs(si,sj,0);//初始位置si,sj和初始时间0
        
        if (escape) cout << "YES" << endl;//可以逃脱输出YES否则输出NO
        else cout << "NO" << endl;
            
    }
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
杭电oj是杭州电子科技大学开发的一个在线评测系统,主要用于计算机考研的教育辅助工具。对于计算机考研的学生来说,杭电oj提供了一个良好的平台,可以进行编程练习和算法训练,帮助学生提升编程能力和算法水平。 首先,杭电oj上有大量的题目库,涵盖了计算机考研的各个方面,比如数据结构、算法设计、数据库等,学生可以根据自己的需要选择相应的题目进行练习。题目难度分级明确,从简单到困难,适合不同水平的学生进行练习。通过解题训练,学生可以熟悉各类算法思想和程序设计方法,提高解题能力。 其次,杭电oj提供了在线评测系统,可以帮助学生及时了解自己的编程能力和代码水平。在解答题目后,杭电oj会自动评判答案的正确性和效率,以及输出格式是否正确。学生可以根据评测结果对自己的代码进行优化和改进,提高编程的正确性和效率。 此外,杭电oj还提供了讨论区功能,学生可以与其他考研学生进行交流和讨论。在讨论区里,学生可以提问、回答问题,分享解题思路和经验,相互学习和进步。通过互助学习,学生可以更好地理解和掌握各类算法和编程知识,提高解题的能力和效率。 总的来说,杭电oj对于计算机考研的学生是一个非常有用的教育辅助工具,它提供了题库、评测系统和讨论区,能够帮助学生提升编程能力和算法水平,提高解题能力和效率。对于计算机考研的学生来说,积极利用杭电oj进行练习和学习,能够有效地提高自己的竞争力和通过考研的概率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值