题目解析:我好想逃却逃不掉 | 豆包MarsCode AI刷题

278 阅读5分钟

题目解析:我好想逃却逃不掉 | 豆包MarsCode AI刷题

问题描述:

给出一个M×N的地图,地图的每个位置有以下可能:

  • .:表示普通地板,可以自由移动到上下左右相邻的格子(不可以走斜线)
  • O:表示出口
  • U:表示向上的传送器,踩上去会被强制传送到上方的格子
  • D:表示向下的传送器,踩上去会被强制传送到下方的格子
  • L:表示向左的传送器,踩上去会被强制传送到左方的格子
  • R:表示向右的传送器,踩上去会被强制传送到右方的格子 

问题是需要找出所有无论如何都不能移动到O的位置个数。

1.思考如何解决

要解决这个问题,我们需要识别出在给定的地图上所有无法到达出口 'O' 的位置。可以通过图搜素算法来解决,在这里考虑到的是采用广度优先搜素算法(BFS)来对地图的每一个点进行遍历。

在这里简单介绍下广度优先搜素算法(BFS)

BFS是一种用于图的遍历或搜索的算法。它从根节点(在这里就是指地图的出口了)开始,逐层遍历地图,直到找到目标节点或遍历完整个图。每次遍历4个方向。

与深度优先搜素算法那样一次遍历一层,遍历到底部为止。不同的是,他是一次遍历一层,遍历4个方向。

对于这个问题,最好是用到广度优先搜素,如果采用深度优先搜素的话,在遇到传送器时可能会不断循环,因为它会沿着路径深入直到无法继续为止。并且由于递归的性质,同一个位置可能会被多次访问

2.具体思路

要解决这个问题,我们可以按照以下步骤进行:

2.1初始化

  • 创建一个 visited 二维数组,用于记录每个位置能否访问到出口。
  • 创建一个 queue,用于存储BFS过程中的节点。

2.2寻找出口

  • 遍历地图,找到所有标记为 'O' 的出口位置,并将这些位置加入 queue,同时将它们标记为能访问到出口。

2.3广度优先搜索从出口开始遍历地图(BFS)

  • 使用BFS从每个出口开始遍历地图,标记所有可达的位置。
  • 定义了一个 directions 字典,用于存储四个不同方向的移动。
  • 在BFS过程中,对于每个当前位置,检查它的四个方向(上、下、左、右)以及传送器的效果。
  • 在确保没超出地图边界的情况下,对队列queue中每个方向进行遍历。
  • 如果遇到传送器,需要特殊处理。
  • 如果遇到普通地板,因为我们是从出口开始进行遍历,如果我们遇到普通地板,说明能从这个普通地板直接访问到出口。则将其加入 queue 并标记这个普通地板能访问到出口。

2.4传送器的处理逻辑

  • 对于传送器的处理,需要检查传送器指向的位置,如果该位置也是传送器,则继续传送,直到找到普通地板或边界。
  • 如果找到的普通地板是能够访问到出口的,则标记这个传送器也能访问到出口
  • 如果是边界,则跳过这个方向
  • 如果传送器形成了一个闭环(例如,一个向右的传送器后面紧跟着一个向左的传送器),也跳过这个方向。

2.5统计危险位置

  • BFS完成后,遍历整个地图,统计所有不能访问到出口的位置(即 visited 数组中值为 False 的位置)。
  • 这些位置就是无论如何都无法到达出口的位置,即“危险位置”。 具体流程大概如下:

image.png

3.代码实现

def solution(N, M, data):
    # Edit your code here
    visited = [[False] * M for _ in range(N)]
    # 找到出口位置
    queue = []
    for i in range(N):
        for j in range(M):
            if data[i][j] == 'O':
                queue.append((i, j))
                visited[i][j] = True   
    # 定义方向数组,用于处理普通移动
    directions = {
        'U': (-1, 0),
        'D': (1, 0),
        'L': (0, -1),
        'R': (0, 1)
    } 
    # 广度优先搜索
    while queue:
        x, y = queue.pop(0)
        for direction, (dx, dy) in directions.items():
            nx, ny = x + dx, y + dy
            # 检查是否在边界内
            if 0 <= nx < N and 0 <= ny < M:
                # 是否是传送器
                if data[nx][ny] in directions:
                    # 处理传送器
                    tx, ty = nx, ny
                    reverse = False
                    while data[tx][ty] in directions:
                        dx, dy = directions[data[tx][ty]]
                        tx += dx
                        ty += dy
                        if not (0 <= tx < N and 0 <= ty < M) or (tx == nx and ty == ny):
                            reverse = True
                            break
                    if 0 <= tx < N and 0 <= ty < M and visited[tx][ty] and not reverse:
                        queue.append((nx, ny))
                        visited[nx][ny] = True
                elif not visited[nx][ny]:
                    queue.append((nx, ny))
                    visited[nx][ny] = True
            else:
                continue     
    # 统计危险位置数量
    danger_count = 0
    for i in range(N):
        for j in range(M):
            if not visited[i][j] and data[i][j] != '#':
                danger_count += 1
    return danger_count

4.心得总结

  就我个人而言,我觉得我刷题的速度是非常缓慢的,可能是对数据结构和算法掌握的不够扎实的缘故,因为我大学是人工智能专业,学校对这方面的要求不高。有了AI刷题的帮助,确实帮了很大的忙。

  不过我是觉得很多算法题目的流程都是差不多的,题目会给你一定的要求和限制,然后让你将代码写出来,这要求我们不仅要理解算法的一般流程,还要能够灵活应对特殊情况

 还有一些问题想问问大家,从就业的角度来讲,刷题是不是很重要呢?