找到竞技场中危险位置的数量 | 豆包MarsCode AI刷题

10 阅读4分钟

找到竞技场中危险位置的数量 | 豆包MarsCode AI刷题

我好想逃却逃不掉 - MarsCode

目前最棘手的模拟题,要用到dfs来做,条件比较多,要细心处理

摘要

在这道题目中,我们需要确定竞技场迷宫中哪些位置是“危险位置”。危险位置的定义为:无论采取何种移动策略,站在这些位置上都无法到达出口。本文将通过深度优先搜索(DFS)算法从出口出发,找出所有可以到达出口的格子,并统计剩余的无法到达的格子数量。


问题描述

竞技场迷宫

迷宫为一个 N×MN \times M 的二维地图,包含以下几种元素:

  • .:普通地板,可以自由移动到上下左右相邻的格子。
  • O:出口。
  • U:向上的传送器,踩上去会被传送到上方的格子。
  • D:向下的传送器,踩上去会被传送到下方的格子。
  • L:向左的传送器,踩上去会被传送到左方的格子。
  • R:向右的传送器,踩上去会被传送到右方的格子。
目标

统计迷宫中所有的“危险位置”数量。即无论如何移动,无法到达出口的位置。


算法原理

为了计算结果,我们采用如下步骤:

  1. 找到出口:首先遍历地图,确定出口所在的坐标。
  2. 深度优先搜索 (DFS)
    • 从出口出发,探索所有可以到达的格子。
    • 如果当前位置是普通地板或传送器,则标记其为“可到达”,并继续探索相邻或传送方向的格子。
  3. 统计结果
    • 对于每个格子,检查是否被标记为“可到达”。如果不是,则计入危险位置。

解题步骤

数据结构
  1. visited:记录每个位置是否已访问,防止重复计算。
  2. canWalk:记录从出口可以到达的所有位置。
传送器处理

对于传送器,根据传送规则直接跳转到对应的格子进行递归。


实现代码

Go 实现
package main

import "fmt"

// visited 数组,用于记录每个位置是否已被访问
var visited [][]bool

// solution 函数:计算无法到达出口的位置数量
func solution(N, M int, data [][]rune) int {
	exitX, exitY := 0, 0
	foundExit := false

	// 找到迷宫出口
	for i := 0; i < N; i++ {
		for j := 0; j < M; j++ {
			if data[i][j] == 'O' {
				exitX = i
				exitY = j
				foundExit = true
				break
			}
		}
		if foundExit {
			break
		}
	}

	// 初始化 visited 数组和 canWalk 数组
	visited = make([][]bool, N)
	canWalk := make([][]bool, N)
	for i := 0; i < N; i++ {
		visited[i] = make([]bool, M)
		canWalk[i] = make([]bool, M)
	}
	canWalk[exitX][exitY] = true // 标记出口为可达
	dfs(N, M, data, exitX, exitY, canWalk)

	// 统计无法到达出口的位置数量
	unreachableCount := 0
	for i := 0; i < N; i++ {
		for j := 0; j < M; j++ {
			if !canWalk[i][j] {
				unreachableCount++
			}
		}
	}
	return unreachableCount
}

// dfs 函数:深度优先搜索,标记所有可到达出口的位置
func dfs(N, M int, data [][]rune, x, y int, canWalk [][]bool) {
	// 判断是否越界或已经访问过
	if x < 0 || x >= N || y < 0 || y >= M {
		return
	}
	if visited[x][y] {
		return
	}

	// 标记当前位置为已访问
	visited[x][y] = true
	// 标记当前位置为可到达
	canWalk[x][y] = true

	// 向上检查
	if x-1 >= 0 && (data[x-1][y] == 'D' || data[x-1][y] == '.') {
		dfs(N, M, data, x-1, y, canWalk)
	}
	// 向下检查
	if x+1 < N && (data[x+1][y] == 'U' || data[x+1][y] == '.') {
		dfs(N, M, data, x+1, y, canWalk)
	}
	// 向左检查
	if y-1 >= 0 && (data[x][y-1] == 'R' || data[x][y-1] == '.') {
		dfs(N, M, data, x, y-1, canWalk)
	}
	// 向右检查
	if y+1 < M && (data[x][y+1] == 'L' || data[x][y+1] == '.') {
		dfs(N, M, data, x, y+1, canWalk)
	}
}

func main() {
	pattern := [][]rune{
		{'.', '.', '.', '.', '.'},
		{'.', 'R', 'R', 'D', '.'},
		{'.', 'U', '.', 'D', 'R'},
		{'.', 'U', 'L', 'L', '.'},
		{'.', '.', '.', '.', 'O'},
	}
	// 输出结果是否为 10
	fmt.Println(solution(5, 5, pattern) == 10)
}
Python 实现
def solution(N, M, data):
    """
    计算无法到达出口的位置数量。
    """
    # 找到迷宫出口
    exit_x, exit_y = 0, 0
    for i in range(N):
        for j in range(M):
            if data[i][j] == 'O':
                exit_x, exit_y = i, j
                break

    # 初始化 visited 和 can_walk 数组
    visited = [[False for _ in range(M)] for _ in range(N)]
    can_walk = [[False for _ in range(M)] for _ in range(N)]

    # 出口是可到达的
    can_walk[exit_x][exit_y] = True

    # 深度优先搜索
    def dfs(x, y):
        # 判断是否越界或已访问
        if x < 0 or x >= N or y < 0 or y >= M or visited[x][y]:
            return
        # 标记当前位置
        visited[x][y] = True
        can_walk[x][y] = True

        # 上
        if x - 1 >= 0 and (data[x - 1][y] == 'D' or data[x - 1][y] == '.'):
            dfs(x - 1, y)
        # 下
        if x + 1 < N and (data[x + 1][y] == 'U' or data[x + 1][y] == '.'):
            dfs(x + 1, y)
        # 左
        if y - 1 >= 0 and (data[x][y - 1] == 'R' or data[x][y - 1] == '.'):
            dfs(x, y - 1)
        # 右
        if y + 1 < M and (data[x][y + 1] == 'L' or data[x][y + 1] == '.'):
            dfs(x, y + 1)

    # 开始从出口位置进行搜索
    dfs(exit_x, exit_y)

    # 统计无法到达出口的位置数量
    unreachable_count = 0
    for i in range(N):
        for j in range(M):
            if not can_walk[i][j]:
                unreachable_count += 1

    return unreachable_count


if __name__ == "__main__":
    pattern = [
        ['.', '.', '.', '.', '.'],
        ['.', 'R', 'R', 'D', '.'],
        ['.', 'U', '.', 'D', 'R'],
        ['.', 'U', 'L', 'L', '.'],
        ['.', '.', '.', '.', 'O']
    ]
    # 输出结果是否为 10
    print(solution(5, 5, pattern) == 10)