1. 网格路径计数(含障碍物)
1.1. 问题描述
给定一个 m x n 的网格,其中某些格子有障碍物不能通过。机器人从左上角 (0, 0) 出发,每次只能向右或向下移动一步,问到达右下角 (m-1, n-1) 有多少条不同的路径?
输入格式:
第一行:两个整数 m 和 n(1 ≤ m, n ≤ 100),表示网格的行数和列数
接下来 m 行:每行 n 个整数(0 或 1),0 表示可通过的空格子,1 表示障碍物
输出格式:
一个整数,表示不同路径的数量
示例输入:
3 3
0 0 0
0 1 0
0 0 0
示例输出:
2
1.2. 分析
1. 理解问题:这是一个典型的动态规划问题。我们需要计算从起点到终点的所有可能路径,但要考虑障碍物的限制。
2. 确定状态:定义 dp[i][j] 表示从 (0,0) 到达 (i,j) 的路径数量。
3. 状态转移方程:对于每个格子 (i,j),

-
如果它是障碍物(grid[i][j] == 1),则 dp[i][j] = 0(无法到达)
-
否则,dp[i][j] = dp[i-1][j] + dp[i][j-1](从上边或左边来的路径之和)
4. 初始化
-
dp[0][0]:如果起点不是障碍物,则为1,否则为0
-
第一行和第一列需要特殊处理,因为它们只能从一个方向来
5. 边界条件
-
当 i=0 或 j=0 时,只能从左边或上边来
-
遇到障碍物时,该点的路径数置为0
6. 计算顺序:按行或按列顺序计算,确保计算 dp[i][j] 时 dp[i-1][j] 和 dp[i][j-1] 已经计算过
7. 最终结果:dp[m-1][n-1] 即为所求
1.3. 代码
def uniquePathsWithObstacles(grid):
m = len(grid) # 网格的行数
n = len(grid[0]) # 网格的列数
# 创建一个 m x n 的二维数组来存储路径数
dp = [[0] * n for _ in range(m)]
# 初始化起点
dp[0][0] = 1 if grid[0][0] == 0 else 0
# 初始化第一列:只能从上边来
for i in range(1, m):
if grid[i][0] == 0: # 当前格子不是障碍物
dp[i][0] = dp[i-1][0] # 只能从上边来
else:
dp[i][0] = 0 # 遇到障碍物,路径数为0
# 初始化第一行:只能从左边来
for j in range(1, n):
if grid[0][j] == 0: # 当前格子不是障碍物
dp[0][j] = dp[0][j-1] # 只能从左边来
else:
dp[0][j] = 0 # 遇到障碍物,路径数为0
# 填充剩余网格
for i in range(1, m):
for j in range(1, n):
if grid[i][j] == 1: # 如果是障碍物
dp[i][j] = 0
else:
# 路径数 = 从上边来的路径数 + 从左边来的路径数
dp[i][j] = dp[i-1][j] + dp[i][j-1]
return dp[m-1][n-1]
# 读取输入
m, n = map(int, input().split())
grid = []
for _ in range(m):
row = list(map(int, input().split()))
grid.append(row)
# 计算并输出结果
print(uniquePathsWithObstacles(grid))
时间复杂度:O(m×n),需要遍历整个网格一次。
空间复杂度:O(m×n),用于存储 dp 数组。可以优化到 O(n) 或 O(m) 使用滚动数组。
对于示例输入:
3 3
0 0 0
0 1 0
0 0 0
dp 数组的填充过程:
-
初始化 dp[0][0] = 1
-
第一列:dp[1][0] = 1, dp[2][0] = 1
-
第一行:dp[0][1] = 1, dp[0][2] = 1
-
dp[1][1] = 0(因为 grid[1][1] 是障碍物)
-
dp[1][2] = dp[0][2] + dp[1][1] = 1 + 0 = 1
-
dp[2][1] = dp[1][1] + dp[2][0] = 0 + 1 = 1
-
dp[2][2] = dp[1][2] + dp[2][1] = 1 + 1 = 2
<