图论的一些python实现

最短路径问题:

Dijkstra算法
import heapq

def dijkstra(adj_list, start):
    # 初始化距离字典
    distances = {node: float('inf') for node in adj_list}
    distances[start] = 0

    # 优先队列,存储 (距离, 节点) 元组
    pq = [(0, start)]

    while pq:
        # 弹出距离最小的节点
        dist, node = heapq.heappop(pq)

        # 如果当前距离大于已知最短距离,则跳过
        if dist > distances[node]:
            continue

        # 遍历邻居节点
        for neighbor, weight in adj_list[node]:
            # 计算新的距离
            new_dist = distances[node] + weight

            # 如果新的距离更短,则更新距离字典和优先队列
            if new_dist < distances[neighbor]:
                distances[neighbor] = new_dist
                heapq.heappush(pq, (new_dist, neighbor))

    return distances


# 示例使用
adj_list = {
    'A': [('B', 2), ('C', 4)],
    'B': [('A', 2), ('C', 1), ('D', 5)],
    'C': [('A', 4), ('B', 1), ('D', 3)],
    'D': [('B', 5), ('C', 3)]
}

start_node = 'A'
distances = dijkstra(adj_list, start_node)

print("Shortest distances from node", start_node)
for node, distance in distances.items():
    print("To node", node, "- Distance:", distance)
Floyd-Warshall算法
import sys

def floyd_warshall(adj_matrix):
    n = len(adj_matrix)

    # 创建一个新的矩阵来存储最短路径长度
    dist = [[0] * n for _ in range(n)]

    # 初始化最短路径矩阵为邻接矩阵
    for i in range(n):
        for j in range(n):
            dist[i][j] = adj_matrix[i][j]

    # 通过中间节点的遍历更新最短路径矩阵
    for k in range(n):
        for i in range(n):
            for j in range(n):
                dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j])

    return dist


# 示例使用
# 用sys.maxsize表示无穷大
inf = sys.maxsize

# 示例邻接矩阵
adj_matrix = [
    [0, 5, inf, 10],
    [inf, 0, 3, inf],
    [inf, inf, 0, 1],
    [inf, inf, inf, 0]
]

# 调用floyd_warshall函数计算最短路径矩阵
shortest_paths = floyd_warshall(adj_matrix)

# 打印最短路径矩阵
print("Shortest Paths:")
for row in shortest_paths:
    print(row)

最小生成树问题:

Prim算法
1.未优化
import heapq

def prim(adj_list):
    # 选取任意一个节点作为起始节点
    start_node = list(adj_list.keys())[0]
    
    # 初始化访问状态和最小生成树
    visited = {node: False for node in adj_list}
    visited[start_node] = True
    min_spanning_tree = []

    # 优先队列,存储 (边权重, 起始节点, 目标节点) 元组
    pq = [(weight, start_node, neighbor) for neighbor, weight in adj_list[start_node]]
    heapq.heapify(pq)

    while pq:
        # 弹出权重最小的边
        weight, src, dest = heapq.heappop(pq)

        # 如果目标节点已访问,则跳过
        if visited[dest]:
            continue

        # 将边加入最小生成树
        min_spanning_tree.append((src, dest, weight))

        # 将目标节点标记为已访问
        visited[dest] = True

        # 将目标节点的邻居边加入优先队列
        for neighbor, weight in adj_list[dest]:
            if not visited[neighbor]:
                heapq.heappush(pq, (weight, dest, neighbor))

    return min_spanning_tree


# 示例使用
adj_list = {
    'A': [('B', 2), ('C', 4)],
    'B': [('A', 2), ('C', 1), ('D', 5)],
    'C': [('A', 4), ('B', 1), ('D', 3)],
    'D': [('B', 5), ('C', 3)]
}

min_spanning_tree = prim(adj_list)

print("Minimum Spanning Tree:")
for src, dest, weight in min_spanning_tree:
    print(src, "--", dest, ": Weight =", weight)
2.减少目标节点的访问次数,只需进行两次比较 
import heapq
 
def prim(adj_list):
    # 选取任意一个节点作为起始节点
    start_node = list(adj_list.keys())[0]
    
    # 初始化访问状态和最小生成树
    visited = {node: False for node in adj_list}
    visited[start_node] = True
    min_spanning_tree = []
 
    # 优先队列,存储 (边权重, 起始节点, 目标节点) 元组
    pq = [(weight, start_node, neighbor) for neighbor, weight in adj_list[start_node]]
    heapq.heapify(pq)
 
    while pq:
        # 弹出权重最小的边
        weight, src, dest = heapq.heappop(pq)
 
        # 如果目标节点已访问,则跳过
        if visited[dest]:
            continue
 
        # 将边加入最小生成树
        min_spanning_tree.append((src, dest, weight))
 
        # 将目标节点标记为已访问
        visited[dest] = True
 
        # 将目标节点的邻居边加入优先队列(只加入未访问的邻居节点的边)
        for neighbor, weight in adj_list[dest]:
            if not visited[neighbor]:
                # 通过比较目标节点的权重,更新已存在于优先队列中的边
                for i, (old_weight, old_src, old_dest) in enumerate(pq):
                    if old_dest == neighbor and weight < old_weight:
                        pq[i] = (weight, dest, neighbor)
                        heapq.heapify(pq)
                        break
                else:
                    heapq.heappush(pq, (weight, dest, neighbor))
 
    return min_spanning_tree
 
 
# 示例使用
adj_list = {
    'A': [('B', 2), ('C', 4)],
    'B': [('A', 2), ('C', 1), ('D', 5)],
    'C': [('A', 4), ('B', 1), ('D', 3)],
    'D': [('B', 5), ('C', 3)]
}
 
min_spanning_tree = prim(adj_list)
 
print("Minimum Spanning Tree:")
for src, dest, weight in min_spanning_tree:
    print(src, "--", dest, ": Weight =", weight)
kruskal算法 
1.并查集方法判断环
#并查集方法判断是否有环
class DisjointSet:
    def __init__(self, n):
        self.parent = list(range(n))
        self.rank = [0] * n

    def find(self, x):
        # 查找节点的根节点
        if self.parent[x] != x:
            # 路径压缩:将节点的父节点直接设为根节点,减少后续查找时间
            self.parent[x] = self.find(self.parent[x])
        return self.parent[x]

    def union(self, x, y):
        x_root = self.find(x)
        y_root = self.find(y)

        if x_root == y_root:
            return

        if self.rank[x_root] < self.rank[y_root]:
            self.parent[x_root] = y_root
        elif self.rank[x_root] > self.rank[y_root]:
            self.parent[y_root] = x_root
        else:
            self.parent[y_root] = x_root
            self.rank[x_root] += 1


def kruskal(vertices, edges):
    edges.sort(key=lambda x: x[2])  # 按边权重升序排序
    num_vertices = len(vertices)
    min_spanning_tree = []

    ds = DisjointSet(num_vertices)

    for edge in edges:
        src, dest, weight = edge
        src_root = ds.find(src)
        dest_root = ds.find(dest)

        if src_root != dest_root:
            # 如果边的起始节点和目标节点不在同一个连通分量中,则将它们合并,并将该边加入最小生成树列表
            ds.union(src_root, dest_root)
            min_spanning_tree.append(edge)

    return min_spanning_tree


# 示例使用
vertices = ['A', 'B', 'C', 'D', 'E']
edges = [
    ('A', 'B', 2),
    ('A', 'C', 3),
    ('B', 'C', 1),
    ('B', 'D', 4),
    ('C', 'D', 2),
    ('C', 'E', 5),
    ('D', 'E', 3)
]

min_spanning_tree = kruskal(vertices, edges)

print("Minimum Spanning Tree:")
for src, dest, weight in min_spanning_tree:
    print(src, "--", dest, ": Weight =", weight)
2.是否添加新节点判断有环
def kruskal(vertices, edges):
    num_vertices = len(vertices)
    added_to_tree = [False] * num_vertices  # 记录顶点是否已添加到树中
    min_spanning_tree = []

    edges.sort(key=lambda x: x[2])  # 按边权重升序排序

    for edge in edges:
        src, dest, weight = edge
        src_index = vertices.index(src)
        dest_index = vertices.index(dest)

        if not added_to_tree[src_index] or not added_to_tree[dest_index]:
            min_spanning_tree.append(edge)
            added_to_tree[src_index] = True
            added_to_tree[dest_index] = True

    return min_spanning_tree


# 示例使用
vertices = ['A', 'B', 'C', 'D', 'E']
edges = [
    ('A', 'B', 2),
    ('A', 'C', 3),
    ('B', 'C', 1),
    ('B', 'D', 4),
    ('C', 'D', 2),
    ('C', 'E', 5),
    ('D', 'E', 3)
]

min_spanning_tree = kruskal(vertices, edges)

print("Minimum Spanning Tree:")
for src, dest, weight in min_spanning_tree:
    print(src, "--", dest, ": Weight =", weight)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值