最小生成树:克鲁斯卡尔与普利姆

普利姆:

普利姆每次选取不在MST(最小生成树)中的点,直到图中所有点都在MST中,但它比较贪,所以选的点是离MST距离最近的点;由于选的是不在MST中的点,所以肯定不会有环。话不多说直接理步骤:

step1:初始化

  • 创建visited标记MST中的节点
  • 选择初始节点,并在visited中标记
n = len(graph)
    visited = [False] * n
    visited[start] = True

step2:选边

  • 从在MST的节点出发,查找所有相邻边(查找在MST中的点的与不在MST中的邻居点的边),选出权重最小的
  • 更新状态,重复上条步骤,直至,所有点包含在MST中
count = n - 1
    while count:
        count -= 1
        min_edge = float('inf')
        min_vertex = -1
        for i in range(n):
            for j in range(n):
                if visited[i] and graph[i][j] > 0:
                    if not visited[j]:
                        if graph[i][j] < min_edge:
                            min_edge = graph[i][j]
                            min_vertex = j

        # 想要总权重,就加最小权重看需求
        # min_all += min_edge
        if min_vertex == -1:
            print("图不连通。")
            break  # 如果没有找到最小边,结束循环
        # 更新状态
        visited[min_vertex] = True

克鲁斯卡尔:

克鲁斯卡尔比较单纯好想,每一步选所有边中的最短边,但它有个问题,那就是因为是随机选的,不像prim一头在MST一头不在MST肯定不会有环;一般用并查集判断环,我的并查集写的比较简单,有强迫症的朋友想要加height的,勿喷;我是有需求才会用。

照旧,上步骤:

step1:初始化

  • 每个点暂时都自立为王都是一个集合
  • 把边抽出来
def find_father(x):
    if x != father[x]:
        father[x] = find_father(father[x])
        return father[x]
def kruskal():
    # 初始化
    n = len(graph)
    for i in range(n):
        father[i] = i

    edges = []
    for i in range(n):
        for j in range(n):
            if graph[i][j] > 0:
                edges.append((i, j, graph[i][j]))

    edges.sort(key=lambda e: e[2], reverse=True) #按权重排序

step2:选边更新状态

  • 选择权重最短的边,如果两节点不在一个集合,说明无环,加入,反之,不加入
  • 当集合大小为图的大小时终止
    # 选边
    mst_edges = []
    while edges:
        # 这句判断可有可无,最后都会停下来
        if len(mst_edges) == n - 1: 
            break
        edge = edges.pop()
        s = edge[0]
        e = edge[1]
        if find_father(s) != find_father(e): # 环的判断
            father[s] = e # 合并到一个集合
            mst_edges.append(edge)

完整代码:
 

def find_father(x):
    if x != father[x]:
        father[x] = find_father(father[x])
        return father[x]

def kruskal():
    # 初始化
    n = len(graph)
    for i in range(n):
        father[i] = i

    edges = []
    for i in range(n):
        for j in range(n):
            if graph[i][j] > 0:
                edges.append((i, j, graph[i][j]))

    edges.sort(key=lambda e: e[2], reverse=True) #按权重排序
    # 选边
    mst_edges = []
    while edges:
        # 这句判断可有可无,最后都会停下来
        if len(mst_edges) == n - 1:
            break
        edge = edges.pop()
        s = edge[0]
        e = edge[1]
        if find_father(s) != find_father(e): # 环的判断
            father[s] = e # 合并到一个集合
            mst_edges.append(edge)
            
    return mst_edges

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值