postgraduate-prep/subjects/major/图论常见算法.md

222 lines
5.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

## 图论常见算法
### Dijkstra算法
用于求解单个源最短路问题:
1. 初始化将所有顶点的距离设为正无穷源顶点设为0
2. 迭代:从源顶点出发,遍历所有边,更新顶点的距离;
3. 检验:检查是否存在负权重环,如果有则返回错误;
4. 返回:返回所有顶点的距离。
### Bellman-Ford算法
#### 数学公式
对于图 $G=(V,E)$Bellman-Ford算法通过迭代松弛更新每个顶点的最短路径估计
$$d(v) = \min\{d(u) + w(u,v) | (u,v) \in E\}$$
其中:
- $d(v)$ 是从源顶点到顶点 $v$ 的最短路径估计
- $w(u,v)$ 是边 $(u,v)$ 的权重
- 迭代次数最多为 $|V|-1$ 次
#### Python实现
```python
def bellman_ford(graph, source):
"""
Bellman-Ford算法求单源最短路径
参数:
graph: 邻接表表示的图,格式 {u: [(v, w), ...]}
source: 源顶点
返回:
distances: 各顶点到源顶点的最短距离
"""
# 初始化距离
distances = {v: float('inf') for v in graph}
distances[source] = 0
# 获取所有顶点
vertices = list(graph.keys())
# 最多进行 |V|-1 次迭代
for _ in range(len(vertices) - 1):
# 对每条边进行松弛操作
for u in graph:
for v, w in graph[u]:
if distances[u] != float('inf') and distances[u] + w < distances[v]:
distances[v] = distances[u] + w
# 检测负权重环
for u in graph:
for v, w in graph[u]:
if distances[u] != float('inf') and distances[u] + w < distances[v]:
raise ValueError("图中存在负权重环")
return distances
# 示例使用
if __name__ == "__main__":
# 构建图 (邻接表)
graph = {
'A': [('B', 4), ('C', 2)],
'B': [('C', 3), ('D', 2), ('E', 3)],
'C': [('B', 1), ('D', 4)],
'D': [('E', -5)], # 负权重边
'E': []
}
try:
distances = bellman_ford(graph, 'A')
print("Bellman-Ford 结果:", distances)
except ValueError as e:
print(e)
```
---
## 常用算法Python实现
### 1. Dijkstra算法
#### 数学公式
Dijkstra算法维护一个优先队列每次选取具有最小距离估计的顶点
$$d(v) = \min_{u \in S} \{ d(u) + w(u,v) \}$$
其中 $S$ 是已确定最短路径的顶点集合。
#### Python实现
```python
import heapq
def dijkstra(graph, source):
"""
Dijkstra算法求单源最短路径
参数:
graph: 邻接表表示的图,格式 {u: [(v, w), ...]}
source: 源顶点
返回:
distances: 各顶点到源顶点的最短距离
"""
# 初始化距离
distances = {v: float('inf') for v in graph}
distances[source] = 0
# 优先队列: (距离, 顶点)
pq = [(0, source)]
visited = set()
while pq:
# 取出最小距离的顶点
current_dist, u = heapq.heappop(pq)
# 如果已访问则跳过
if u in visited:
continue
visited.add(u)
# 更新邻接顶点的距离
for v, w in graph.get(u, []):
if v not in visited and current_dist + w < distances[v]:
distances[v] = current_dist + w
heapq.heappush(pq, (distances[v], v))
return distances
# 示例使用
if __name__ == "__main__":
# 构建图 (邻接表)
graph = {
'A': [('B', 4), ('C', 2)],
'B': [('C', 3), ('D', 2), ('E', 3)],
'C': [('B', 1), ('D', 4)],
'D': [('E', 5)],
'E': []
}
distances = dijkstra(graph, 'A')
print("Dijkstra 结果:", distances)
# 输出: {'A': 0, 'B': 3, 'C': 2, 'D': 5, 'E': 8}
```
### 2. Bellman-Ford算法
#### 数学公式
对于图 $G=(V,E)$Bellman-Ford算法通过迭代松弛更新每个顶点的最短路径估计
$$d(v) = \min\{d(u) + w(u,v) | (u,v) \in E\}$$
其中:
- $d(v)$ 是从源顶点到顶点 $v$ 的最短路径估计
- $w(u,v)$ 是边 $(u,v)$ 的权重
- 迭代次数最多为 $|V|-1$ 次
#### Python实现
```python
def bellman_ford(graph, source):
"""
Bellman-Ford算法求单源最短路径
参数:
graph: 邻接表表示的图,格式 {u: [(v, w), ...]}
source: 源顶点
返回:
distances: 各顶点到源顶点的最短距离
"""
# 初始化距离
distances = {v: float('inf') for v in graph}
distances[source] = 0
# 获取所有顶点
vertices = list(graph.keys())
# 最多进行 |V|-1 次迭代
for _ in range(len(vertices) - 1):
# 对每条边进行松弛操作
for u in graph:
for v, w in graph[u]:
if distances[u] != float('inf') and distances[u] + w < distances[v]:
distances[v] = distances[u] + w
# 检测负权重环
for u in graph:
for v, w in graph[u]:
if distances[u] != float('inf') and distances[u] + w < distances[v]:
raise ValueError("图中存在负权重环")
return distances
# 示例使用
if __name__ == "__main__":
# 构建图 (邻接表)
graph = {
'A': [('B', 4), ('C', 2)],
'B': [('C', 3), ('D', 2), ('E', 3)],
'C': [('B', 1), ('D', 4)],
'D': [('E', -5)], # 负权重边
'E': []
}
try:
distances = bellman_ford(graph, 'A')
print("Bellman-Ford 结果:", distances)
except ValueError as e:
print(e)
```