做小生成树和最短路径问题

img


这个实验怎么做?怎么生成最小生气成树和解决最短路径问题。麻烦各位帮我解决一下。

  • 你可以看下这个问题的回答https://ask.csdn.net/questions/7511025
  • 这篇博客也不错, 你可以看下【数据结构与算法】最小生成树与最短路径问题
  • 您还可以看一下 张传波老师的软件设计是怎样炼成的?课程中的 架构设计的第一层拆解小节, 巩固相关知识点
  • 以下回答由chatgpt基于相关博客总结生成:

    回答:

    小生成树问题:

    1. 理解什么是小生成树:给定一个连通的无向图,找出一棵生成树,使得这棵树上所有边权之和最小。

    2. 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]
    
    1. Prim算法:从一个起始点开始,选择与该点相连的边中权值最小的,将其加入生成树中,然后继续选择与已选边相连的未选择的边中权值最小的,重复操作直到所有点都被包含在生成树中。

    参考代码:(假设图用邻接表存储,每个元素包含目标节点和边的权值)

    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
    

    最短路径问题:

    1. 理解什么是最短路径:给定一个加权有向图和起点,找到起点到指定节点的最短路径。

    2. 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
    
    1. Floyd-Warshall算法:使用动态规划的方法,先初始化任意两点之间的距离,然后不断更新任意两点之间通过中间节点的距离,直到最终距离矩阵不再更新。

    参考代码:(假设图用邻接矩阵存储)

    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