222 lines
5.4 KiB
Markdown
222 lines
5.4 KiB
Markdown
## 图论常见算法
|
||
|
||
### 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)
|
||
```
|