ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2021-01-21 18:59:05  阅读:240  来源: 互联网

标签:tmp index edge total1 最小 edges 关键 1489 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) 数对都是互不相同的。

最小生成树
一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的最少的边。 最小生成树可以用kruskal(克鲁斯卡尔)算法或prim(普里姆)算法求出。

克鲁斯卡尔(Kruskal)算法
克鲁斯卡尔算法是求连通网的最小生成树的另一种方法。与普里姆算法不同,它的时间复杂度为O(eloge)(e为网中的边数),所以,适合于求边稀疏的网的最小生成树。

克鲁斯卡尔(Kruskal)算法从另一途径求网的最小生成树。其基本思想是:假设连通网G=(V,E),令最小生成树的初始状态为只有n个顶点而无边的非连通图T=(V,{}),图中每个顶点自成一个连通分量。在E中选择代价最小的边,若该边依附的顶点分别在T中不同的连通分量上,则将此边加入到T中;否则,舍去此边而选择下一条代价最小的边。依此类推,直至T中所有顶点构成一个连通分量为止。

解题思路:

Kruskal算法思想、并查集

代码:

class Solution:
    def findCriticalAndPseudoCriticalEdges(self, n: int, edges: List[List[int]]) -> List[List[int]]:
        parent = list(range(n))
        def find(index):
            if index != parent[index]:
                parent[index] = find(parent[index])
            return parent[index]
        def union(index1, index2):
            parent[index2] = index1
        
        # 在这里由小到大排序,就是Kruskal的思想
        # 在原有的edge中添加位置索引,方便排序后能得到在原edges中的位置
        sorted_edges = [[index] + i for index, i in enumerate(edges)]
        # 根据 weight 对边进行排序
        sorted_edges = sorted(sorted_edges, key=lambda x:x[-1])


        # 计算最小生成树的权值和total
        total = 0
        for index, (_, x, y, w) in enumerate(sorted_edges):
            rx, ry = find(x), find(y)
            if rx != ry:
                union(rx, ry)
                total += w
        

        # 接下来进行 最小生成树的构造,分为两种情况:
        # 1、先连接当前边,得到所有连通边的权值和tmp_total1
        # 2、去掉当前边,得到所有连通边的权值和tmp_total2

        # 然后total、tmp_total1、tmp_total2进行比较
        # 若total与tmp_total1相等,则代表该边为有效边,否则为无效边直接跳过
        # 然后若tmp_total1不等于tmp_total2,则代表该边为关键边,否则为伪关键边

        key_edge = []  # 关键边列表
        no_key_edge = []  # 非关键边列表
        for i, edge in enumerate(sorted_edges):
            (_, cx, cy, cw) = edge
            # 去掉当前边,形成新的边列表
            tmp_edges = sorted_edges[:i] + sorted_edges[i+1:]


            # 1、先连接当前边,得到连通边的权值和tmp_total1
            total1 = cw
            parent = list(range(n))
            union(cx, cy)
            for index, (_,x,y,w) in enumerate(tmp_edges):
                rx, ry = find(x), find(y)
                if rx != ry:
                    union(rx, ry)
                    total1 += w

            # 2、去掉当前边,得到连通边的权值和tmp_total2
            total2 = 0
            parent = list(range(n))
            for index, (_,x,y,w) in enumerate(tmp_edges):
                rx, ry = find(x), find(y)
                if rx != ry:
                    union(rx, ry)
                    total2 += w

            # 然后total、total1、total2进行比较
            # 若total与total1相等,则代表该边为有效边,否则为无效边直接跳过
            # 然后若total1不等于total2,则代表该边为关键边,否则为伪关键边
            if total1 == total:
                if total1 != total2:
                    key_edge.append(edge[0])
                else:
                    no_key_edge.append(edge[0])
            
        return [key_edge, no_key_edge]

提交记录:
在这里插入图片描述

标签:tmp,index,edge,total1,最小,edges,关键,1489,LeetCode
来源: https://blog.csdn.net/qq_51771374/article/details/112938202

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有