1. 问题描述:
给定一个 N 行 M 列的 01 矩阵 A,A[i][j] 与 A[k][l] 之间的曼哈顿距离定义为:
dist(A[i][j],A[k][l])=|i−k|+|j−l|
输出一个 N 行 M 列的整数矩阵 B,其中:
B[i][j]=min1≤x≤N,1≤y≤M,A[x][y]=1dist(A[i][j],A[x][y])
输入格式
第一行两个整数 N,M。接下来一个 N 行 M 列的 01 矩阵,数字之间没有空格。
输出格式
一个 N 行 M 列的矩阵 B,相邻两个整数之间用一个空格隔开。
数据范围
1 ≤ N,M ≤ 1000
输入样例:
3 4
0001
0011
0110
输出样例:
3 2 1 0
2 1 0 0
1 0 0 1
来源:https://www.acwing.com/problem/content/description/175/
2. 思路分析:
分析题目可以知道我们需要求解多个起点到其余点的最短距离,属于多源最短路径问题,这里需要与多源多汇最短路径要区分开,多源多汇最短路求解的是任意两点之间的最短距离,而这里求解的是多个起点到其余点的最短距离,对于这种多源最短路径问题其实可以转化为单源最短路径问题,我们只需要建一个虚拟源点,从虚拟源点向所有起点连一条权重为0的边,但是在实际写代码的时候并不需要将虚拟源点建立出来,我们只需要将所有起点加入到队列中,并且将最短距离初始化为0的做法是等价的,这里与图论中求解多个起点到其余点的最短路径中的思想是类似的,都是借助于虚拟源点的思想,加入多个起点之后与之前单源bfs的步骤是一样的。
3. 代码如下:
import collections
from typing import List
class Solution:
def bfs(self, n: int, m: int, q: collections.deque, g: List[str], dis: List[List[int]]):
# 右左下上四个方向
pos = [[0, 1], [0, -1], [1, 0], [-1, 0]]
while q:
x0, y0 = q.popleft()
for i in range(4):
a, b = x0 + pos[i][0], y0 + pos[i][1]
if a < 0 or a >= n or b < 0 or b >= m: continue
# 之前有位置到达过当前的点说明最短距离已经求解出来了直接跳过
if dis[a][b] != -1: continue
# 求解到达当前点的最短距离
dis[a][b] = dis[x0][y0] + 1
# 加入到队列中
q.append((a, b))
for i in range(n):
for j in range(m):
print(dis[i][j], end=" ")
print()
def process(self):
n, m = map(int, input().split())
g = list()
for i in range(n):
g.append(input())
q = collections.deque()
# dis可以记录最短距离并且判重
dis = [[-1] * (m + 10) for i in range(n + 10)]
for i in range(n):
for j in range(m):
# 将值为1的位置加入到队列中并且最短距离更新为0
if g[i][j] == "1":
q.append((i, j))
dis[i][j] = 0
self.bfs(n, m, q, g, dis)
if __name__ == '__main__':
Solution().process()