最小化穿越黑色格子的迷宫路径算法解析
在最近的编程挑战中,我遇到了一个有趣的问题:帮助小S在一个n×m的网格迷宫中从左上角(1,1)移动到右下角(n,m),同时尽可能少地经过黑色格子。这个问题不仅考验了我的算法设计能力,还锻炼了我的逻辑思维和优化技巧。以下是我对这个问题的理解和解题思路。
问题描述
小S在一个n×m的网格迷宫中,初始位置在左上角(1,1),目标是到达右下角(n,m)。每个格子可以是黑色(表示为1)或者白色(表示为0)。他希望在移动过程中经过的黑色格子尽可能少。移动时可以向上、下、左、右四个方向移动,但不能走出迷宫的边界。
输入和输出
- 输入:
- n: 迷宫的行数。
- m: 迷宫的列数。
- grid: 一个n×m的二维数组,表示迷宫,其中1表示黑色格子,0表示白色格子。
- 输出: 从起点到终点所需经过的最少黑色格子的数量。
问题介绍
我们需要在一个n×m的网格迷宫中,从左上角(1,1)移动到右下角(n,m),并且希望经过的黑色格子(值为1的格子)尽可能少。
数据结构与算法选择
- 网格表示:使用二维数组grid来表示迷宫。
- 访问状态:可以使用一个二维数组visited来记录每个格子是否已经被访问过。
- 队列:使用队列来进行广度优先搜索(BFS),因为BFS可以保证找到的路径是最短路径。
算法步骤
-
初始化:
- 创建一个队列,并将起点(0, 0)入队。
- 创建一个二维数组visited来记录每个格子是否已经被访问过。
- 创建一个二维数组blackCount来记录到达每个格子时经过的最少黑色格子数量。
-
BFS遍历:
- 从队列中取出一个格子(x, y)。
- 检查它的四个相邻格子(x+1, y), (x-1, y), (x, y+1), (x, y-1):
- 如果相邻格子在网格范围内且未被访问过,则将其入队。
- 更新blackCount数组,记录到达该格子时经过的最少黑色格子数量。
-
终止条件:
- 当到达终点(n-1, m-1)时,返回blackCount[n-1][m-1]。
实现代码
以下是这个问题的一个简单实现:
from collections import deque
def minimumBlackTiles(n, m, grid):
# 初始化队列,visited数组和blackCount数组
queue = deque([(0, 0, grid[0][0])])
visited = [[False] * m for _ in range(n)]
visited[0][0] = True
blackCount = [[0] * m for _ in range(n)]
blackCount[0][0] = grid[0][0]
# 四个方向的移动
directions = [(0, 1), (1, 0), (0, -1), (-1, 0)]
# BFS
for x, y, count in queue:
if x == n - 1 and y == m - 1:
return count
for dx, dy in directions:
nx, ny = x + dx, y + dy
if 0 <= nx < n and 0 <= ny < m and not visited[nx][ny]:
visited[nx][ny] = True
new_count = count + grid[nx][ny]
blackCount[nx][ny] = min(blackCount[nx][ny], new_count)
queue.append((nx, ny, new_count))
return blackCount[n-1][m-1]
# 示例
n = 5
m = 5
grid = [[1, 1, 0, 0, 0],
[0, 1, 0, 0, 1],
[1, 0, 0, 1, 1],
[0, 0, 1, 0, 0],
[1, 0, 1, 1, 0]]
print(minimumBlackTiles(n, m, grid)) # 输出:2
实践感悟
通过这个问题,我深刻体会到了广度优先搜索(BFS)在解决最短路径问题中的应用。BFS可以保证我们找到的路径是最短路径,这对于最小化穿越黑色格子的问题至关重要。