LeetCode(1489. 找到最小生成树里的关键边和伪关键边&&Python)

该博客详细解析了LeetCode中的1489题,介绍了如何使用克鲁斯卡尔算法寻找带权无向图最小生成树中的关键边和伪关键边。通过Python实现,利用并查集模板,首先找到最小生成树的最小权值,然后通过删除每一条边并重新计算最小生成树的权值来判断边的类型。关键边是删除后权值增加的边,而伪关键边可能出现在某些最小生成树中。
摘要由CSDN通过智能技术生成

LeetCode(1489. 找到最小生成树里的关键边和伪关键边)


给你一个 n 个点的带权无向连通图,节点编号为 0 到 n-1 ,同时还有一个数组 edges ,其中 edges[i] = [fromi, toi, weighti] 表示在 fromi 和 toi 节点之间有一条带权无向边。最小生成树 (MST) 是给定图中边的一个子集,它连接了所有节点且没有环,而且这些边的权值和最小。

请你找到给定图中最小生成树的所有关键边和伪关键边。如果从图中删去某条边,会导致最小生成树的权值和增加,那么我们就说它是一条关键边。伪关键边则是可能会出现在某些最小生成树中但不会出现在所有最小生成树中的边。

请注意,你可以分别以任意顺序返回关键边的下标和伪关键边的下标。

 

示例 1:

输入:n = 5, edges = [[0,1,1],[1,2,1],[2,3,2],[0,3,2],[0,4,3],[3,4,3],[1,4,6]]
输出:[[0,1],[2,3,4,5]]
解释:上图描述了给定图。
下图是所有的最小生成树。

注意到第 0 条边和第 1 条边出现在了所有最小生成树中,所以它们是关键边,我们将这两个下标作为输出的第一个列表。
边 2,3,4 和 5 是所有 MST 的剩余边,所以它们是伪关键边。我们将它们作为输出的第二个列表。
示例 2 :

输入:n = 4, edges = [[0,1,1],[1,2,1],[2,3,1],[0,3,1]]
输出:[[],[0,1,2,3]]
解释:可以观察到 4 条边都有相同的权值,任选它们中的 3 条可以形成一棵 MST 。所以 4 条边都是伪关键边。
 

提示:

2 <= n <= 100
1 <= edges.length <= min(200, n * (n - 1) / 2)
edges[i].length == 3
0 <= fromi < toi < n
1 <= weighti <= 1000
所有 (fromi, toi) 数对都是互不相同的。

来源:力扣(LeetCode)
链接:题目链接

题解:Python解法的kruskal算法

class Solution:
    def __init__(self):self.MAX_VALUE = 1e6
    def find(self, prev, node):       # 并查集模板
        if prev[node] != node:prev[node] = self.find(prev, prev[node])  # 路径压缩
        return prev[node]
    def kruskal(self, edges, n, k, remove=True):   # 克鲁斯卡尔算法找最小生成树
        prev = [i for i in range(n)]
        count, cost = 0, 0
        if not remove:                             # 必包含第k条边
            prev[self.backup[k][1]] = self.backup[k][0]
            cost = self.backup[k][2]
            count = 1
        for i, edge in enumerate(edges):
            if remove and k >= 0 and edge == self.backup[k]:continue  # 特殊情况不包含
            p1, p2 = self.find(prev, edge[0]), self.find(prev, edge[1])
            if p1 == p2: continue    # 同一棵树直接跳过
            prev[p2] = p1            # 两树合并
            cost += edge[2]
            count += 1
            if count == n - 1:return cost
        return self.MAX_VALUE
    def findCriticalAndPseudoCriticalEdges(self, n: int, edges: List[List[int]]) -> List[List[int]]:
        self.backup = [edge for edge in edges] # 保持顺序 不用深拷贝
        edges.sort(key=lambda x : x[2])        # 升序排序
        minCost = self.kruskal(edges, n, -1)
        result = [[], []]
        for i in range(len(edges)):
            if self.kruskal(edges, n, i) > minCost:result[0].append(i) # 关键边
            elif self.kruskal(edges, n, i, False) == minCost: result[1].append(i)  # 伪关键边
        return result

 

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值