Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >LeetCode 1489. 找到最小生成树里的关键边和伪关键边(并查集+kruskal最小生成树)

LeetCode 1489. 找到最小生成树里的关键边和伪关键边(并查集+kruskal最小生成树)

作者头像
Michael阿明
发布于 2021-02-19 06:55:01
发布于 2021-02-19 06:55:01
99000
代码可运行
举报
运行总次数:0
代码可运行

文章目录

1. 题目

给你一个 n 个点的带权无向连通图,节点编号为 0 到 n-1 ,同时还有一个数组 edges ,其中 edges[i] = [fromi, toi, weighti] 表示在 fromi 和 toi 节点之间有一条带权无向边。

最小生成树 (MST) 是给定图中边的一个子集,它连接了所有节点且没有环,而且这些边的权值和最小。

请你找到给定图中最小生成树的所有关键边和伪关键边。

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

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

示例 1:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
输入: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 :

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
输入: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) 链接:https://leetcode-cn.com/problems/find-critical-and-pseudo-critical-edges-in-minimum-spanning-tree 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

2. 解题

图–最小生成树 并查集参考

  • 解题见注释
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class dsu{  //并查集
    vector<int> f;
public:
    dsu(int n)
    {
        f.resize(n);
        for(int i = 0; i < n; ++i)
            f[i] = i;
    }
    void merge(int a, int b)
    {
        int fa = find(a), fb = find(b);
        if(fa != fb)
        {
            f[fa] = fb;
        }
    }
    int find(int a)
    {
        if(a == f[a]) return a;
        return f[a] = find(f[a]);
    }
    void reset()
    {
        for(int i = 0; i < f.size(); ++i)
            f[i] = i;
    }
};
class Solution {
public:
    vector<vector<int>> findCriticalAndPseudoCriticalEdges(int n, vector<vector<int>>& edges) {
        vector<int> edgeId(edges.size());
        iota(edgeId.begin(), edgeId.end(), 0);
        sort(edgeId.begin(), edgeId.end(),[&](auto a, auto b){
            return edges[a][2] < edges[b][2];//距离小的优先
        });
        dsu u(n);
        vector<bool> vis(edges.size(), false);
        int mincost = kruskal(vis, u, edgeId, edges, n, 0);//最小生成树权值
        vector<vector<int>> ans(2);
        for(int i = 0; i < edges.size(); ++i)
        {
            vis[i] = true;//删除这条边
            u.reset();//重置并查集
            int cost = kruskal(vis, u, edgeId, edges, n, 0);
            if(cost > mincost)//删除边以后,cost 变大,或 无法生成树
            {
                ans[0].push_back(i);//关键边
                vis[i] = false;
                continue;
            }
            u.reset();//重置并查集
            u.merge(edges[i][0], edges[i][1]);//不是关键边,且提前把这条边加入树中
            cost = kruskal(vis, u, edgeId, edges, n, edges[i][2]);
            if(cost == mincost)// 权值和 不变,伪关键边
                ans[1].push_back(i);
            vis[i] = false;//恢复这条边
        }
        return ans;
    }
    int kruskal(vector<bool>& vis, dsu& u, vector<int>& edgeId, vector<vector<int>>& edges, int n, int mincost)
    {
        int edge_count = (mincost ? 1 : 0);//提前加入边了吗
        int a, b, id, cost;
        for(int i = 0; i < edgeId.size(); ++i)
        {
            id = edgeId[i];
            if(vis[id]) continue;//边删除了
            a = edges[id][0];
            b = edges[id][1];
            cost = edges[id][2];
            if(u.find(a) != u.find(b))
            {
                u.merge(a, b);
                mincost += cost;
                edge_count++;
            }
            if(edge_count == n-1)
                return mincost;
        }
        return INT_MAX;//无法构造生成树
    }
};

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021/01/21 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
LeetCode 1135. 最低成本联通所有城市(最小生成树+排序+并查集)
想象一下你是个城市基建规划者,地图上有 N 座城市,它们按以 1 到 N 的次序编号。
Michael阿明
2021/02/19
2.4K0
LeetCode周赛194总结
这次来参加了一下194周赛,做完前两道,后面第三道思路不太对,写错了,就差了一个函数调用。。最后一道是一个prim/kruskal算法求解最小生成树的问题,这两个算法之前也没实现过,于是就不太会做了,下来总结一下这次的题解,互相学习吧,期待下次周赛的进步。
公众号guangcity
2020/06/24
4080
图的应用——最小生成树
最小生成树 生成树(极小连通子图):含有图中全部n个顶点,但只有n-1条边。并且n-1条边不能构成回路。 [在这里插入图片描述] 生成森林:非连通图每个连通分量的生成树一起组成非连通图的生成森林。 [在这里插入图片描述] 求最小生成树 使用不同的遍历图的方法,可以得到不同的生成树 从不同的顶点出发,也可能得到不同的生成树。 按照生成树的定义,n 个顶点的连通网络的生成树有 n 个顶点、n-1 条边。在网的多个生成树中,寻找一个各边权值之和最小的生成树 构造最小生成树的准则 必须只使用该网中的边来构造最小生成
ruochen
2021/06/29
8860
图的应用——最小生成树
图Graph--最小生成树
练习题: LeetCode 1135. 最低成本联通所有城市(最小生成树+排序+并查集) LeetCode 1489. 找到最小生成树里的关键边和伪关键边(并查集+kruskal最小生成树)
Michael阿明
2021/02/20
5160
图Graph--最小生成树
最小生成树学习
生成树:给定无向图G=(V,E),连接G中所有点,且边集是E的n-1条边构成的无向连通子图称为G的生成树(Spanning Tree),而边权值总和最小的生成树称为最小生成树(Minimal Spanning Tree,MST)。
fishhh
2022/10/31
5900
东哥带你刷图论第五期:Kruskal 最小生成树算法
图论中知名度比较高的算法应该就是 Dijkstra 最短路径算法,环检测和拓扑排序,二分图判定算法 以及今天要讲的最小生成树(Minimum Spanning Tree)算法了。
labuladong
2021/11/09
2.2K0
最小生成树算法(下)——Kruskal(克鲁斯卡尔)算法
在我的上一篇文章最小生成树算法(上)——Prim(普里姆)算法 主要讲解对于稠密图较为合适的Prim算法。那么在接下里这片文章中我主要讲解对于稀疏图较为合适的Kruskal算法。
AI那点小事
2020/04/20
1.3K0
最小生成树算法(下)——Kruskal(克鲁斯卡尔)算法
生成树和最小生成树prim,kruskal
普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树。意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点(英语:Vertex (graph theory)),且其所有边的权值之和亦为最小。该算法于1930年由捷克数学家沃伊捷赫·亚尔尼克(英语:Vojtěch Jarník)发现;并在1957年由美国计算机科学家罗伯特·普里姆(英语:Robert C. Prim)独立发现;1959年,艾兹格·迪科斯彻再次发现了该算法。因此,在某些场合,普里姆算法又被称为DJP算法、亚尔尼克算法或普里姆-亚尔尼克算法。 中文名 普里姆算法 外文名 Prim Algorithm 别 称 最小生成树算法 提出者 沃伊捷赫·亚尔尼克(Vojtěch Jarník) 提出时间 1930年 应用学科 计算机,数据结构,数学(图论) 适用领域范围 应用图论知识的实际问题 算 法 贪心 目录 1 算法描述 2 时间复杂度 3 图例描述 4 代码 ▪ PASCAL代码 ▪ c代码 ▪ C++代码 5 时间复杂度 算法描述编辑 1).输入:一个加权连通图,其中顶点集合为V,边集合为E; 2).初始化:Vnew = {x},其中x为集合V中的任一节点(起始点),Enew = {},为空; 3).重复下列操作,直到Vnew = V: a.在集合E中选取权值最小的边,其中u为集合Vnew中的元素,而v不在Vnew集合当中,并且v∈V(如果存在有多条满足前述条件即具有相同权值的边,则可任意选取其中之一); b.将v加入集合Vnew中,将边加入集合Enew中; 4).输出:使用集合Vnew和Enew来描述所得到的最小生成树。
废江_小江
2022/09/05
1K0
最小生成树的Kruskal算法
定义: 一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的最少的边。[1] 最小生成树可以用kruskal(克鲁斯卡尔)算法或prim(普里姆)算法求出。 Kruskal算法简述: 假设 WN=(V,{E}) 是一个含有 n 个顶点的连通网,则按照克鲁斯卡尔算法构造最小生成树的过程为:先构造一个只含 n 个顶点,而边集为空的子图,若将该子图中各个顶点看成是各棵树上的根结点,则它是一个含有 n 棵树的一个森林。之后,从网的边集 E 中选取一条权值最小的
用户3577892
2020/06/12
2.1K0
最小生成树——克鲁斯卡尔(Kruskal)算法
之前学了用普里姆算法来求最小生成树的权值和,但是它的时间复杂度为O(|V2|),使用优先级队列优化后,可以优化为O(|E|log|V|)。
灯珑LoGin
2022/10/31
7700
最小生成树总结
给定一张带权无向图 G=(V,E),n = |V|, m = |E|。由 V 中全部 n 个顶点和 E 中 n-1 条边构成的无向连通子图被称为 G 的一棵生成树。边权和最小的生成树被称为无向图 G 的最小生成树(Minimum Spanning Tree,MST)。
Here_SDUT
2022/06/29
1.3K0
POJ 1679:The Unique MST(次小生成树&amp;&amp;Kruskal)[通俗易懂]
Given a connected undirected graph, tell if its minimum spanning tree is unique.
全栈程序员站长
2022/07/08
4280
最小生成树判断唯一
题意:若最小生成树唯一则输出权值和,若不唯一输出Not Not Unique! 运用prim算法将最小生成树求出,然后在依次枚举删除最小生成树中的每一条边,判断是否还能构成一个新的最小生成树,且权值和与初始的权值和相等,若能构成则不唯一 #include<stdio.h> #include<stdlib.h> #include<vector> using namespace std; /*看了很久才相处为什么要用这个stl 假设v,u都为最小生成树中的点,但是 v,u所扩展出来的最小生成树边却不一定相等 所
用户1624346
2018/04/11
9890
使用贪心算法解决最小生成树问题
大家好,我是 V 哥。今天跟大家聊一聊贪心算法问题,因为遇到这个面试题,问贪心算法解决最小生成树是怎么设计的,以及如何应用?好家伙,这面试官一上来就不按套路出牌,直接上难度,如果你遇到这样的问题,该怎么办呢。下面 V 哥来详细聊一聊。
威哥爱编程
2025/01/22
1640
数据结构:最小生成树算法模板prim和kruskal(考研)
1.prim #include <iostream> #include <cstring> #include <algorihtm> using namespace std; const int N=510; const int INF=0x3f3f3f3f; int dist[N];//保存距离 bool st[N];//标记点是否已经被访问过 int g[N][N];//邻接矩阵存储图 int n, m; //返回值为最小生成树的权值 int prim() { memset(dist, INF
lexingsen
2022/02/24
3460
最小生成树-Prim算法和Kruskal算法
Prim算法 1.概览 普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树。意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点(英语:Vertex (graph theory)),且其所有边的权值之和亦为最小。该算法于1930年由捷克数学家沃伊捷赫·亚尔尼克(英语:Vojtěch Jarník)发现;并在1957年由美国计算机科学家罗伯特·普里姆(英语:Robert C. Prim)独立发现;1959年,艾兹格·迪科斯彻再次发现了该算法。因此,在某些场合,普里姆算
用户1215536
2018/02/05
3.9K0
最小生成树-Prim算法和Kruskal算法
【c++高阶DS】最小生成树
连通图中的每一棵生成树,都是原图的一个极大无环子图,即:从其中删去任何一条边,生成树就不在连通;反之,在其中引入任何一条新边,都会形成一条回路,且这些边的权值之和最小
用户11029103
2024/12/28
2040
【c++高阶DS】最小生成树
最小生成树,克鲁斯卡尔算法入门。
带权图:边赋以权值的图称为网或带权图,带权图的生成树也是带权的,生成树T各边的权值总和称为该树的权。
全栈程序员站长
2021/12/23
5130
数据结构基础温故-5.图(中):最小生成树算法
图的“多对多”特性使得图在结构设计和算法实现上较为困难,这时就需要根据具体应用将图转换为不同的树来简化问题的求解。
Edison Zhou
2018/08/20
1.2K0
数据结构基础温故-5.图(中):最小生成树算法
数据结构 最小生成树之Kruskal算法
首先构造一个只含n个顶点的森林,然后依权值从小到大从连通网中选择边加入到森林中,并使森林不产生回路,直至森林变成过一棵树为止
Twcat_tree
2022/11/29
5450
数据结构 最小生成树之Kruskal算法
推荐阅读
相关推荐
LeetCode 1135. 最低成本联通所有城市(最小生成树+排序+并查集)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验