回答:
小生成树问题:
理解什么是小生成树:给定一个连通的无向图,找出一棵生成树,使得这棵树上所有边权之和最小。
Kruskal算法:先将所有边按权值从小到大排序,然后从最小的边开始选择,如果该边两个端点不在同一连通分量内,就将其加入生成树中。重复操作直到所有的边都被考虑过。
参考代码:(假设图用数组edges存储,每个元素包含起点、终点和权值)
def kruskal(n, edges):
# 并查集初始化
parent = [i for i in range(n)]
size = [1 for i in range(n)]
# 边按权值排序
edges.sort(key=lambda x: x[2])
# 结果数组
res = []
# 遍历所有边
for u, v, w in edges:
# 查询两个端点所在的连通分量
pu, pv = find(parent, u), find(parent, v)
# 如果不在同一连通分量内,则加入生成树中
if pu != pv:
res.append([u, v, w])
union(parent, size, pu, pv)
return res
# 并查集查找
def find(parent, x):
if parent[x] != x:
parent[x] = find(parent, parent[x])
return parent[x]
# 并查集合并
def union(parent, size, p, q):
if size[p] < size[q]:
parent[p] = q
size[q] += size[p]
else:
parent[q] = p
size[p] += size[q]
参考代码:(假设图用邻接表存储,每个元素包含目标节点和边的权值)
import heapq
def prim(graph, start):
# 结果集和已访问集合
res, visited = [], set()
# 优先队列,存放边,按权值排序
pq = [(0, start)]
# 执行n-1次循环
while pq and len(res) < len(graph) - 1:
# 取出当前最小边
weight, u = heapq.heappop(pq)
# 如果u已经访问过则跳过
if u in visited:
continue
# 标记u已访问
visited.add(u)
# 将当前最小边加入结果集
res.append((u, weight))
# 遍历与u相邻的边
for v, w in graph[u]:
# 如果v还未访问,则将(u, v)加入优先队列
if v not in visited:
heapq.heappush(pq, (w, v))
return res
最短路径问题:
理解什么是最短路径:给定一个加权有向图和起点,找到起点到指定节点的最短路径。
Dijkstra算法:从起点开始,每次选择当前距离起点最近的节点,然后更新与该节点直接相连的节点的距离,重复操作直到所有节点都被考虑过。
参考代码:(假设图用邻接表存储,每个元素包含目标节点和边的权值)
import heapq
def dijkstra(graph, start):
# 节点个数
n = len(graph)
# 距离数组和已访问集合
dist = [float('inf')] * n
visited = [False] * n
# 起点距离为0
dist[start] = 0
# 优先队列,存放节点和到起点的距离,按距离排序
pq = [(0, start)]
# Dijkstra算法
while pq:
# 取出距离起点最近的节点
d, u = heapq.heappop(pq)
# 如果u已经访问过则跳过
if visited[u]:
continue
# 标记u已访问
visited[u] = True
# 遍历与u相邻的节点
for v, w in graph[u]:
# 如果新距离比原距离小,则更新距离数组
if not visited[v] and dist[u] + w < dist[v]:
dist[v] = dist[u] + w
# 将v加入优先队列
heapq.heappush(pq, (dist[v], v))
return dist
参考代码:(假设图用邻接矩阵存储)
def floyd_warshall(graph):
# 节点个数
n = len(graph)
# 初始化距离矩阵
dist = [[float('inf')] * n for _ in range(n)]
for i in range(n):
for j in range(n):
if i == j:
dist[i][j] = 0
elif graph[i][j] != 0:
dist[i][j] = graph[i][j]
# Floyd算法
for k in range(n):
for i in range(n):
for j in range(n):
if dist[i][j] > dist[i][k] + dist[k][j]:
dist[i][j] = dist[i][k] + dist[k][j]
return dist