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

5.4 KiB
Raw Blame History

图论常见算法

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实现

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实现

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实现

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)