# 多源BFS——AcWing 173. 矩阵距离 from collections import deque
defmain(): n, m = map(int, input().split()) g = [list(input()) for _ inrange(n)] dist = [[-1] * m for _ inrange(n)] dx = [-1, 0, 1, 0] dy = [0, -1, 0, 1] defbfs(): q = deque() for i inrange(n): for j inrange(m): if g[i][j] == '1': q.append((i, j)) dist[i][j] = 0 while q: x, y = q.popleft() for i inrange(4): a, b = x + dx[i], y + dy[i] if a < 0or a >= n or b < 0or b >= m: continue if dist[a][b] != -1: continue q.append((a, b)) dist[a][b] = dist[x][y] + 1
bfs() # for i in range(n): # for j in range(m): # print(dist[i][j], end=" ") # print() [print(' '.join([str(x) for x in r])) for r in dist] # 速度快很多
// 双端队列BFS——AcWing 175. 电路维修 // 边权不唯一,既有0又有1(0 and not 0) #include<cstring> #include<iostream> #include<algorithm> #include<deque> #define x first #define y second
usingnamespace std;
typedef pair<int, int> PII; constint N = 510, M = N * N;
int n, m; char g[N][N]; int dist[N][N]; // 这里要注意g[N][N]存的是边的状态图,而dist[N][N]存的是节点间的距离 // 因此两者的坐标是不同的,前者是边的坐标,后者是节点的坐标,不能混淆,需要分别进行定义表示 bool st[N][N]; // 类似dijkstra算法,一个节点会多次入队,需要判重数组,防止多次更新
while (q.size()){ PII t = q.front(); q.pop_front();
if (st[t.x][t.y]) continue; // 不重复更新,类堆优化 Dijkstra 的判重方式 st[t.x][t.y] = true;
// 对电线的走向、走过的方格进行遍历 for (int i = 0; i < 4; i ++ ){ int a = t.x + dx[i], b = t.y + dy[i]; // 节点的坐标->记录节点距离 if (a < 0 || a > n || b < 0 || b > m) continue; // 注意这里上界是n和m,而不是n-1和m-1
int ca = t.x + ix[i], cb = t.y + iy[i]; // 边的坐标->读边的当前状态 int d = dist[t.x][t.y] + (g[ca][cb] != cs[i]); // 根据边的状态是否是连通状态来判断边权
if (d < dist[a][b]){ // 只有距离更短才进行更新 dist[a][b] = d;
# 双端队列BFS——AcWing 175. 电路维修 # 边权不唯一,既有0又有1(0 and not 0) from collections import deque
defmain(): T = int(input()) es = "\\/\\/" # 四个方向通路时的状态,以左上角方格为起点顺时针记录,呈 X 型 d_x, d_y = [-1, -1, 1, 1], [-1, 1, 1, -1] # 节点的对应坐标,指经过此方向的电线后可到达的点,以左上角方格顺时针编号 d_ex, d_ey = [-1, -1, 0, 0], [-1, 0, 0, -1] # 边的对应坐标,注意这里的相对坐标也是相对节点而言的,因为入队的是节点 # 指此方向的电线将经过的田子格(边状态),以左上角方格顺时针编号 defbfs(): dist = [[1e9] * (m + 1) for _ inrange(n + 1)] # 一定注意这里上界是n和m,而不是n-1和m-1 dist[0][0] = 0 dq = deque([(0, 0)]) vis = set() # 不重复更新,类堆优化 Dijkstra 的判重方式 while dq: x, y = dq.popleft() if (x, y) in vis: continue vis.add((x, y)) for ch, dx, dy, dex, dey inzip(es, d_x, d_y, d_ex, d_ey): nx, ny = x + dx, y + dy if nx < 0or nx > n or ny < 0or ny > m: continue ex, ey = x + dex, y + dey d = dist[x][y] + int(g[ex][ey] != ch) # 根据边的状态是否是连通状态来判断边权 if d < dist[nx][ny]: dist[nx][ny] = d if g[ex][ey] == ch: dq.appendleft((nx, ny)) else: dq.append((nx, ny)) # 边权为0的插入队头,边权为1的插入队尾 # 这样维持了两段性和单调性 return dist[n][m]
for _ inrange(T): n, m = map(int, input().split()) g = [input() for _ inrange(n)] # 这里要注意g存的是边的状态图,而dist存的是节点间的距离 res = bfs() print("NO SOLUTION"if res == 1e9else res)
# BFS之最小步数模型——外部搜索——AcWing 1107. 魔板 # 不含dist的简化版 from collections import deque
defmain(): start, end = "12345678", "".join(input().split()) # A 操作等价于是翻转原字符串,B、C 操作可以在草稿纸上同理推出 # 无需转数组,可减少代码量 A = lambda s: s[::-1] B = lambda s: s[3] + s[:3] + s[5:] + s[4] C = lambda s: s[0] + s[6] + s[1] + s[3:5] + s[2] + s[5] + s[7] pre = {} defbfs(): q = deque([start]) pre[start] = ("", "")
while q: t = q.popleft() if t == end: s = pre[t][0] returnstr(len(s)), s for op, nextinzip("ABC", (A(t), B(t), C(t))): ifnextnotin pre: pre[next] = (pre[t][0] + op, t) q.append(next) return - 1 print("\n".join(bfs()).strip()) # 这里最后输出不需要判断操作序列为空的情况是因为strip()去掉了空,避免了第二个换行符