最小生成树——Prim/Kruskal Python

最小生成树

从一个图中,生成一个权重最小的生成树

Prim

朴素版 O ( n 2 ) O(n^2) O(n2) 稠密图

不断重复以下过程:

  • 选择与当前集合距离最近的点,加入集合
  • 拓展当前集合

和Dijsktra的思想类似,每次拓展与当前集合最近的点(而不再是原点)
对应的唯一区别就是

for j in range(1, n+1):
        dis[j] = min(dis[j], g[t][j])

在Prim里是直接取g[t][j],而dijsktra是取dis[t]+g[t][j]

n,m = map(int, input().split())

g = [[float('inf') ] * (n+1) for _ in range(n+1)]

dis = [float('inf') ]* (n+1)

for i in range(m):
    x,y,z = map(int, input().split())
    g[x][y] = min(g[x][y], z)
    g[y][x] = g[x][y]

st = [False] *(n+1)

res = 0
for i in range(n):
    t = -1
    # 找到距离集合最近的点
    for j in range(1,n+1):
        if not st[j] and (t == -1 or dis[j] < dis[t]):
            t = j
    if i:
        res += dis[t]
    st[t] = True

    for j in range(1, n+1):
        dis[j] = min(dis[j], g[t][j])

if res == float('inf'):
    print('impossible')
else:
    print(res)

优化版 O ( m log ⁡ n ) O(m \log{n}) O(mlogn)

和迪杰斯特拉的优化方式一样,使用堆来优化,改成bfs,每次取出队列中距离集合最短的点拓展。

Kruskal 稀疏图

算法流程:

  • 将所有的边按权重从小到大排序
  • 每次取出权重最小的边,如果两个点不属于一个集合,融合他们(并查集)
import heapq


n,m = map(int, input().split())
# 首先读入所有的边,存入堆中
edges = []
for i in range(m):
    x,y,z = map(int, input().split())
    edges.append((z,x,y))

heapq.heapify(edges)
# 设置n个点的并查集
s = [i for i in range(n+1)]

def find(x):
    if s[x] != x:
        s[x] = find(s[x])
    return s[x]

# 开始出堆,每次取出堆顶元素,融合集合
res = 0
cnt = 0
while edges:
    t = heapq.heappop(edges)
    z,x,y = t
    if find(x) != find(y):
        s[find(x)] = find(y)
        res += z
        cnt += 1

if cnt == n-1:
    print(res)
else:
    print('impossible')
  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

volcanical

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值