多源BFS,即同时存在多个起点,然后要求计算出图中任意一个点距离所有起点的最短距离,即图中任意点到每个起点的距离的最小值。
一般单源BFS求最短路,是针对于单一起点来说计算图中其他点到起点的最短距离。多源BFS有多个起点,可以将所有起点看成一个整体,计算图中其他点到这个起点的最短距离。操作上只需要将单源BFS起始加入队列的单一起点,变为所有起点。
给定一个 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
from collections import deque
N = 1010
DIRC = [[-1, 0], [0, 1], [1, 0], [0, -1]]
g = []
dist = [[-1] * N for _ in range(N)]
def bfs() :
que = deque()
for i in range(n) :
for j in range(m) :
if g[i][j] == '1' :
que.appendleft([i, j])
dist[i][j] = 0
while len(que) != 0 :
x, y = que.pop()
for i in range(4) :
a, b = x + DIRC[i][0], y + DIRC[i][1]
if a < 0 or a >= n or b < 0 or b >= m : continue
if dist[a][b] != -1 : continue
que.appendleft([a, b])
dist[a][b] = dist[x][y] + 1
n, m = map(int, input().split())
for i in range(n) :
g.append(input())
bfs()
for i in range(n) :
for j in range(m) :
print(dist[i][j], end = " ")
print()
BFS最短路模型,所有状态一般都是基于一个点向周围的点扩散的状态。每次只需要保存每次扩散遍历的点的状态即可,整个图本身不变。最小步数模型,每一步都会改变图的状态,此时我们需要保存的是图的状态。
Rubik 先生在发明了风靡全球的魔方之后,又发明了它的二维版本——魔板。
这是一张有 8 个大小相同的格子的魔板:
1 2 3 4
8 7 6 5
我们知道魔板的每一个方格都有一种颜色。
这 8 种颜色用前 8 个正整数来表示。
可以用颜色的序列来表示一种魔板状态,规定从魔板的左上角开始,沿顺时针方向依次取出整数,构成一个颜色序列。
对于上图的魔板状态,我们用序列 (1,2,3,4,5,6,7,8) 来表示,这是基本状态。
这里提供三种基本操作,分别用大写字母 A,B,C 来表示(可以通过这些操作改变魔板的状态):
A:交换上下两行;
B:将最右边的一列插入到最左边;
C:魔板中央对的4个数作顺时针旋转。
下面是对基本状态进行操作的示范:
A:
8 7 6 5
1 2 3 4
B:
4 1 2 3
5 8 7 6
C:
1 7 2 4
8 6 3 5
对于每种可能的状态,这三种基本操作都可以使用。
你要编程计算用最少的基本操作完成基本状态到特殊状态的转换,输出基本操作序列。
注意:数据保证一定有解。
输入格式
输入仅一行,包括 8 个整数,用空格分开,表示目标状态。
输出格式
输出文件的第一行包括一个整数,表示最短操作序列的长度。
如果操作序列的长度大于0,则在第二行输出字典序最小的操作序列。
数据范围
输入数据中的所有数字均为 1 到 8 之间的整数。
输入样例:
2 6 8 4 5 7 3 1
输出样例:
7
BCABCCB
from collections import deque
g = [[0] * 4 for _ in range(2)]
dist = dict()
pre = dict()
def set(state) :
for i in range(4) : g[0][i] = state[i]
j = 4
for i in range(3, -1, -1) :
g[1][i] = state[j]
j += 1
def get() :
res = ''
for i in range(4) : res += g[0][i]
for i in range(3, -1, -1) : res += g[1][i]
return res
def move0(state) :#上下行变换
set(state)
for i in range(4) :
g[0][i], g[1][i] = g[1][i], g[0][i]
return get()
def move1(state) :#将最右边的一列插入到最左边
set(state)
v0, v1 = g[0][3], g[1][3]
for i in range(3, 0, -1) :
g[0][i], g[1][i] = g[0][i - 1], g[1][i - 1]
g[0][0], g[1][0] = v0, v1
return get()
def move2(state) : #魔板中央对的4个数作顺时针旋转
set(state)
v = g[0][1]
g[0][1] = g[1][1]
g[1][1] = g[1][2]
g[1][2] = g[0][2]
g[0][2] = v
return get()
def bfs(st, ed) :
if st == ed : return 0
que = deque()
que.appendleft(st)
dist[st] = 0
while len(que) :
t = que.pop()
m = []
m.append(move0(t))
m.append(move1(t))
m.append(move2(t))
for i in range(3) :
if dist.get(m[i], -1) == -1 :
que.appendleft(m[i])
dist[m[i]] = dist[t] + 1
pre[m[i]] = [chr(ord('A') + i), t]
if m[i] == ed : return dist[ed]
ed = "".join(list(map(str, input().split())))
st = '12345678'
step = bfs(st, ed)
print(step)
res = ''
while ed != st :
res += pre[ed][0]
ed = pre[ed][1]
if step > 0 :
print(res[:: -1])
只要每一步都是分量相同,则可考虑BFS