小S的黑白块迷宫| 豆包MarsCode AI 刷题

37 阅读3分钟

问题描述

小S在一个n×mn×m的网格迷宫中,初始位置在左上角 (1,1)(1,1),目标是到达右下角 (n,m)(n,m)。每个格子可以是黑色(表示为1)或者白色(表示为0)。他希望在移动过程中经过的黑色格子尽可能少。移动时可以向上、下、左、右四个方向移动,但不能走出迷宫的边界。请你帮小S计算从起点到终点所需经过的最少黑色格子的数量。


测试样例

样例1:

输入:n = 5 ,m = 3 ,grid = [[0, 1, 0], [0, 1, 1], [0, 1, 0], [1, 0, 0], [1, 0, 0]]
输出:1

样例2:

输入:n = 4 ,m = 4 ,grid = [[0, 0, 1, 0], [1, 0, 1, 0], [1, 0, 0, 0], [1, 1, 1, 0]]
输出:0

样例3:

输入:n = 3 ,m = 3 ,grid = [[0, 0, 0], [1, 1, 0], [1, 1, 0]]
输出:0

关键点

  1. 网格迷宫:迷宫是一个二维网格,每个格子可以是黑色(1)或白色(0)。
  2. 起点和终点:起点是左上角 (1,1)(1,1),终点是右下角 (n,m)(n,m)
  3. 移动规则:可以向上、下、左、右四个方向移动,但不能走出迷宫的边界。
  4. 目标:找到从起点到终点的路径,使得经过的黑色格子数量最少。

代码分析

  • 定义四个方向的移动
directions = [(-1, 0), (1, 0), (0, -1), (0, 1)]
  • 初始化队列和访问标记数组
queue = deque([(0, 0)])  # 起点 (0, 0)
    visited = [[float('inf')] * m for _ in range(n)]  
  • 记录每个格子到起点的最小黑色格子数量
visited[0][0] = 0 if grid[0][0] == 0 else 1  # 起点如果是黑色格子,初始值为1,否则为0
    
    while queue:
        x, y = queue.popleft()
        
        # 检查四个方向的相邻格子
        for dx, dy in directions:
            nx, ny = x + dx, y + dy
            
            # 检查是否越界
            if 0 <= nx < n and 0 <= ny < m:
                # 计算相邻格子到起点的黑色格子数量
                new_cost = visited[x][y] + (1 if grid[nx][ny] == 1 else 0)
                
                # 如果新路径更优,更新并加入队列
                if new_cost < visited[nx][ny]:
                    visited[nx][ny] = new_cost
                    queue.append((nx, ny)) 
  • 返回终点到起点的最小黑色格子数量
return visited[n-1][m-1]

完整代码演示

from collections import deque

def solution(n: int, m: int, grid: list) -> int:
    directions = [(-1, 0), (1, 0), (0, -1), (0, 1)]
    
    queue = deque([(0, 0)])  
    visited = [[float('inf')] * m for _ in range(n)] 
    visited[0][0] = 0 if grid[0][0] == 0 else 1 
    
    while queue:
        x, y = queue.popleft()
        
        for dx, dy in directions:
            nx, ny = x + dx, y + dy
            
            if 0 <= nx < n and 0 <= ny < m:
                new_cost = visited[x][y] + (1 if grid[nx][ny] == 1 else 0)
                
                if new_cost < visited[nx][ny]:
                    visited[nx][ny] = new_cost
                    queue.append((nx, ny))
    
    return visited[n-1][m-1]

解题思路

  1. 理解问题:需要在网格中找到从起点到终点的路径,使得经过的黑色格子数量最少。
  2. 数据结构选择
    • 使用队列来进行BFS。
    • 使用一个二维数组来记录每个格子到起点的最小黑色格子数量。
  3. 算法步骤
    • 初始化队列,将起点加入队列,并记录起点到起点的黑色格子数量为0。
    • 从队列中取出当前格子,检查其四个方向的相邻格子。
    • 如果相邻格子是有效的(不越界且未访问过),则更新其到起点的黑色格子数量,并将其加入队列。
    • 重复上述步骤,直到队列为空或到达终点。

关键步骤解释

  1. 方向数组directions 用于表示四个方向的移动。
  2. 队列和访问标记数组queue 用于BFS,visited 用于记录每个格子到起点的最小黑色格子数量。
  3. BFS循环:从队列中取出当前格子,检查其相邻格子,更新最小黑色格子数量并加入队列。
  4. 返回结果:最终返回终点到起点的最小黑色格子数量。

总结

通过这个题目能够加深对BFS算法的理解,还能掌握二维数组的操作、队列的使用、动态规划思想以及复杂度分析。这些技能在解决许多其他类似的网格问题和图问题时都非常有用。