算法|图论 6 并查集

news2024/11/15 8:51:09

并查集基本模板:

int n = 10;
vector UFSets(n,0);//若将初值全设置为-1,那就不用再有初始化操作了。

//初始化
void Initial(vector<int> S[]){
    for(int i=0;i<n;i++){
        S[i] = -1;
    }
}

//查操作
int Find(vector<int> &S,int x){
    int root = x;
    while(s[root] >= 0) root = S[root]//先找到x的根
    while(x != root){//压缩路径
        int t = S[x];//首先找到x的父亲,防止一会丢失找不到了
        S[x] = root;//将x挂到根节点下
        x = t;//再让x变为其父亲,将路径上所有节点都直接挂到根上
    }
    return root;
}

void Union(vector<int> &S,int x,int y){
    int Root1 = Find(S,x);
    int Root2 = Find(S,y);
    if(Root1 == Root2) return;
    if(S[Root2] > S[Root1]){//Root2节点数少,应该将其挂在Root1上面
        S[Root1] += S[Root2];//将两个集的节点数加起来
        S[Root2] = Root1;//小树挂到大树上去
    }else{
        S[Root2] += S[Root1];
        S[Root1] = Root2;
    }
    return ;
}

LeetCode 1971- 寻找图中是否存在路径

题目链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

题目描述:有一个具有 n 个顶点的 双向 图,其中每个顶点标记从 0 到 n - 1(包含 0 和 n - 1)。图中的边用一个二维整数数组 edges 表示,其中 edges[i] = [ui, vi] 表示顶点 ui 和顶点 vi 之间的双向边。 每个顶点对由 最多一条 边连接,并且没有顶点存在与自身相连的边。

请你确定是否存在从顶点 source 开始,到顶点 destination 结束的 有效路径

给你数组 edges 和整数 n、source 和 destination,如果从 source 到 destination 存在 有效路径 ,则返回 true,否则返回 false 。

解题思路

使用并查集,初始我们将所有边都每个edges都Union,这样就将连在一起的边都接在同一个树下了,然后再find找到看是否为同一个根,是则返回true,否则返回false。

class Solution {
public:
//初始化
void Initial(vector<int> &S){
    for(int i=0;i<S.size();i++){
        S[i] = -1;
    }
}

//查操作
int Find(vector<int> &S,int x){
    int root = x;
    while(S[root] >= 0) root = S[root];//先找到x的根
    while(x != root){//压缩路径
        int t = S[x];//首先找到x的父亲,防止一会丢失找不到了
        S[x] = root;//将x挂到根节点下
        x = t;//再让x变为其父亲,将路径上所有节点都直接挂到根上
    }
    return root;
}

void Union(vector<int> &S,int x,int y){
    int Root1 = Find(S,x);
    int Root2 = Find(S,y);
    if(Root1 == Root2) return;
    if(S[Root2] > S[Root1]){//Root2节点数少,应该将其挂在Root1上面
        S[Root1] += S[Root2];//将两个集的节点数加起来
        S[Root2] = Root1;//小树挂到大树上去
    }else{
        S[Root2] += S[Root1];
        S[Root1] = Root2;
    }
    return ;
}
    bool validPath(int n, vector<vector<int>>& edges, int source, int destination) {
        vector<int> UFSets(n,-1);//若将初值全设置为-1,那就不用再有初始化操作了。
        for(int i=0;i<edges.size();i++){
            Union(UFSets,edges[i][0],edges[i][1]);
        }
        if(Find(UFSets,source) == Find(UFSets,destination)) return true;
        return false;
    }
};

总结:并查集的Union就可以用来初始化边与边之间的联系,不需要你手动去给每个根和节点赋值。

LeetCode 684- 冗余连接

题目链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

题目描述:树可以看成是一个连通且 无环 的 无向 图。

给定往一棵 n 个节点 (节点值 1~n) 的树中添加一条边后的图。添加的边的两个顶点包含在 1 到 n 中间,且这条附加的边不属于树中已存在的边。图的信息记录于长度为 n 的二维数组 edges ,edges[i] = [ai, bi] 表示图中在 ai 和 bi 之间存在一条边。

请找出一条可以删去的边,删除后可使得剩余部分是一个有着 n 个节点的树。如果有多个答案,则返回数组 edges 中最后出现的那个。

解题思路

和上一题的区别就是我们这次需要删除一条冗余的边。这次我们不直接union节点,我们先判断,若这两条边没有连在一起,也就是根不同,我们再union。若这两条边已经连在一起,就说明现在这条边是冗余的了,我们就直接返回这条边即可。

class Solution {
public:
    int Find(vector<int> &S,int x){
        int root = x;
        while(S[root] >= 0) root = S[root];
        while(x != root){
            int t = S[x];
            S[x] = root;
            x = t;
        }
        return root; 
    }
    void Union(vector<int> &S,int x,int y){
        int root1 = Find(S,x);
        int root2 = Find(S,y);
        if(root1 == root2) return;
        if(S[root1] > S[root2]){//root2根下树叶多一些
            S[root2] += S[root1];
            S[root1] = root2;
        }else{
            S[root1] += S[root2];
            S[root2] = root1;
        }
    }
    vector<int> findRedundantConnection(vector<vector<int>>& edges) {
        vector<int> UFSets(1001,-1);
        for(int i=0;i<edges.size();i++){
            int node1 = edges[i][0];
            int node2 = edges[i][1];
            if(Find(UFSets,node1) != Find(UFSets,node2)) Union(UFSets,node1,node2);
            else return edges[i];
        }
        return vector<int>{};
    }
};

总结:并查集的Union就可以用来建立边与边之间的联系。

LeetCode 685.冗余连接II

题目链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

题目描述:在本问题中,有根树指满足以下条件的 有向 图。该树只有一个根节点,所有其他节点都是该根节点的后继。该树除了根节点之外的每一个节点都有且只有一个父节点,而根节点没有父节点。

输入一个有向图,该图由一个有着 n 个节点(节点值不重复,从 1 到 n)的树及一条附加的有向边构成。附加的边包含在 1 到 n 中的两个不同顶点间,这条附加的边不属于树中已存在的边。

结果图是一个以边组成的二维数组 edges 。 每个元素是一对 [ui, vi],用以表示 有向 图中连接顶点 ui 和顶点 vi 的边,其中 ui 是 vi 的一个父节点。

返回一条能删除的边,使得剩下的图是有 n 个节点的有根树。若有多个答案,返回最后出现在给定二维数组的答案。

解题思路

本题明确告诉我们多了一条边,需要我们删除,然后让图变成树,有三种情况。

  • 情况一(有一个节点入度为2):

  • 情况二:

没有节点入度为2时

  • 情况三(成环):

和上一题的区别就是我们这次需要删除一条边,并且这个图是有向图,难度就上来了。这题的基本思路就是:

  • 首先写出并查集
  • 第二再根据每个edge计算每个节点的入度,(为什么不看出度,因为每个节点都可能有多个出度,只有入度才是别的点到它,说明有多条路径可以走到当前节点,所以看入度)根据题目的描述,只有一个节点的入度会大于1,也就是2。并且只会有两条边导致入度为2,所以我们将这两条边加入待删队列中。然后再判断删除这两条边,图中是否能变成一棵树,如果可以则返回当前这条边,否则返回另一条边。因为这两条边一定有一条是构成环的边,删除就能变成树。
  • 第三,若没有入度为2的边,那一定是情况三,构成环了。我们直接删除构成环的那条边就可以。

class Solution {
private:
    static const int N = 1010; // 如题:二维数组大小的在3到1000范围内
    int father[N];
    int n; // 边的数量
    // 并查集初始化
    void init() {
        for (int i = 1; i <= n; ++i) {
            father[i] = i;
        }
    }
    // 并查集里寻根的过程
    int find(int u) {
        return u == father[u] ? u : father[u] = find(father[u]);
    }
    // 将v->u 这条边加入并查集
    void join(int u, int v) {
        u = find(u);
        v = find(v);
        if (u == v) return ;
        father[v] = u;
    }
    // 判断 u 和 v是否找到同一个根
    bool same(int u, int v) {
        u = find(u);
        v = find(v);
        return u == v;
    }
    // 在有向图里找到删除的那条边,使其变成树
    vector<int> getRemoveEdge(const vector<vector<int>>& edges) {
        init(); // 初始化并查集
        for (int i = 0; i < n; i++) { // 遍历所有的边
            if (same(edges[i][0], edges[i][1])) { // 构成有向环了,就是要删除的边
                return edges[i];
            }
            join(edges[i][0], edges[i][1]);
        }
        return {};
    }

    // 删一条边之后判断是不是树
    bool isTreeAfterRemoveEdge(const vector<vector<int>>& edges, int deleteEdge) {
        init(); // 初始化并查集
        for (int i = 0; i < n; i++) {
            if (i == deleteEdge) continue;
            if (same(edges[i][0], edges[i][1])) { // 构成有向环了,一定不是树
                return false;
            }
            join(edges[i][0], edges[i][1]);
        }
        return true;
    }
public:

    vector<int> findRedundantDirectedConnection(vector<vector<int>>& edges) {
        int inDegree[N] = {0}; // 记录节点入度
        n = edges.size(); // 边的数量
        for (int i = 0; i < n; i++) {
            inDegree[edges[i][1]]++; // 统计入度
        }
        vector<int> vec; // 记录入度为2的边(如果有的话就两条边)
        // 找入度为2的节点所对应的边,注意要倒叙,因为优先返回最后出现在二维数组中的答案
        for (int i = n - 1; i >= 0; i--) {
            if (inDegree[edges[i][1]] == 2) {
                vec.push_back(i);
            }
        }
        // 处理图中情况1 和 情况2
        // 如果有入度为2的节点,那么一定是两条边里删一个,看删哪个可以构成树
        if (vec.size() > 0) {
            if (isTreeAfterRemoveEdge(edges, vec[0])) {
                return edges[vec[0]];
            } else {
                return edges[vec[1]];
            }
        }
        // 处理图中情况3
        // 明确没有入度为2的情况,那么一定有有向环,找到构成环的边返回就可以了
        return getRemoveEdge(edges);

    }
};

总结:并查集的Union就可以用来建立边与边之间的联系。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1012635.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【红包雨压测环境】

文章目录 红包雨压测环境并发预估积分与权重对于新用户&#xff0c;活跃度占比为70%&#xff0c;贡献度占比为30%。活跃度权重分配&#xff1a;贡献度权重分配&#xff1a; 对于高质量作品的作者&#xff0c;活跃度占比为30%&#xff0c;贡献度占比为70%。活跃度指标权重&#…

杭州企业型通配符SSL数字证书

通配符SSL数字证书是众多数字证书产品中比较特殊的一款产品&#xff0c;在互联网安全领域&#xff0c;SSL数字证书是保障网站安全性的一种重要手段。而通配符SSL数字证书&#xff0c;更是其中的一种特殊类型&#xff0c;它允许用户对多个域名进行保护&#xff0c;只需一张证书即…

C++--简单实现定长内存池

1.什么是定长内存池 在C/C中&#xff0c;动态申请内存都是通过malloc来申请的&#xff0c;但是实际上不是是直接从堆上直接申请的内存&#xff0c;而是通过malloc动态申请一大块内存&#xff0c;malloc就相当于一块内存池&#xff0c;然后分给程序使用&#xff0c;如果申请的内…

网络安全进阶学习第十六课——业务逻辑漏洞介绍

文章目录 一、什么是业务逻辑二、业务逻辑漏洞的成因三、逻辑漏洞的重要性四、业务逻辑漏洞分类五、业务逻辑漏洞——业务授权安全1、未授权访问2、越权访问1) 平行越权&#xff08;水平越权是指相同权限的不同用户可以互相访问&#xff09;2) 垂直越权&#xff08;垂直越权是指…

企业架构LNMP学习笔记47

企业架构队列缓存中间件分布式redis&#xff1a; 一直想学习下这块的。今天总算学到了&#xff0c;好好把redis的这块内容理解下。 1&#xff09;能够描述Redis作用及其业务适用场景 &#xff1b; 2&#xff09;能够安装配置启动Redis&#xff1b; 3&#xff09;能够使用命令…

Qt使用注意事项

1.菜单选项不能出现数字&#xff0c;可以是 英文 加 “_”&#xff1a; 2.如何确保加载的图片&#xff0c;尺寸大小与原来一样&#xff1f; 【QT】添加图片资源并使用QImage加载图片显示_qimage显示图片_李春港的博客-CSDN博客 ui->PicLabel->setPixmap(QPixmap::fromIm…

(9.8-9.14)【大数据新闻速递】

加gzh“大数据食铁兽”&#xff0c;了解更多大数据快讯 【2023百度十大科技前沿发明】 近日&#xff0c;百度发布了“2023百度十大科技前沿发明”&#xff0c;包括“基于大模型的检索生成决策交互一体的智能系统”“基于大模型的端到端搜索技术”“飞桨端到端自适应的分布式训…

网络工程师的甩锅指南,果断收藏

大家好&#xff0c;我是老杨。 都说IT行业最容易被甩锅的就是网工&#xff0c;这是有科学依据的&#xff0c;比如&#xff1a; 纵观我网工群的群友聊天&#xff0c;“锅”不离口&#xff0c;很难不说明一点什么问题。 遇到甩锅&#xff0c;我相信没有哪位朋友的心情是愉悦的。…

父子工程搭建

1. 构建父工程 父工程的职责是对依赖包的版本进行管理&#xff0c;创建父工程分两步&#xff0c;第一创建父工程&#xff0c;第二在pom.xml编辑依赖管理。 进入新建模块界面&#xff0c;选择Spring Initializr&#xff0c;填写模块的信息&#xff1a; 创建成功&#xff0c;删…

linux服务器内服务访问域名Name or service not know

目录 linux服务器内服务访问域名Name or service not know 1.前言2.排查是不是这个域名无法访问2.1服务内ping 这个域名2.2在浏览器打开这个域名2.3服务内ping 这个域名所对应的ip2.4在服务器内配置host 总结参考 文章所属专区 项目问题解决 1.前言 linux服务器内服务访问域名…

许可分析 license分析 第五章

许可分析是指对软件许可证进行详细的分析和评估&#xff0c;以了解组织内部对软件许可的需求和使用情况。通过许可分析&#xff0c;可以帮助组织更好地管理和优化软件许可证的使用。以下是一些可能的许可分析方法和步骤&#xff1a; 软件许可证自动化管理&#xff1a;考虑使用自…

飞驰的高铁-第15届蓝桥杯第一次STEMA测评Scratch真题精选

[导读]&#xff1a;超平老师的《Scratch蓝桥杯真题解析100讲》已经全部完成&#xff0c;后续会不定期解读蓝桥杯真题&#xff0c;这是Scratch蓝桥杯真题解析第150讲。 飞驰的高铁&#xff0c;本题是2023年8月20日举行的第15届蓝桥杯STEMA测评Scratch编程中级组编程第2题&#…

字节、京东等大厂年薪50w的测试都什么水平?

各位做测试的朋友&#xff0c;但凡经历过几次面试&#xff0c;那么你一定曾被问到过以下问题&#xff1a; 1、在Linux环境下&#xff0c;怎么执行web自动化测试&#xff1f; 2、Shell如何&#xff0c;Docker熟悉吗&#xff1f; 3、全链路的压测实操过吗&#xff0c;如何推进与开…

hexo搭建一个自己的博客

hexo腾讯云服务器搭建一个自己的博客 我的博客: http://www.elcarimqaq.top/ 前期准备 node.js&#xff1a; https://nodejs.org/en/ git&#xff1a;https://git-scm.com/download/win hexo官方文档&#xff1a;https://hexo.io/zh-cn/docs/index.html 安装hexo npm ins…

“存量竞争” 体验为王,火山引擎边缘云助力内容社区破局

今年4月&#xff0c;在宣布要技术升级、数据重构后&#xff0c;承载无数人青春的天涯社区疑似关停&#xff0c;一代传奇的衰落为所有内容社区释放出了不可忽视的信号。 图片来源&#xff1a;天涯官博 回顾天涯社区发展史&#xff0c;从“周公子大战易烨卿”、天涯十大诡异事件&…

“批量文件改名:将日语文件名翻译成中文,轻松管理你的文件!

如果你经常处理各种文件&#xff0c;可能有时候会遇到一些以日语命名的文件。这时候&#xff0c;为了更好地管理和查找文件&#xff0c;你可能需要将这些日语文件名翻译成中文。那么&#xff0c;如何实现批量将日语文件名翻译成中文呢&#xff1f; 首先&#xff0c;第一步进入…

对抗生成网络总结

对一些基本的对抗生成网络的总结。部分内容整理自Teeyohuang’s blog 文章目录 GAN (NeurIPS, 2014)CGANDCGANStackGANPix2Pix (CVPR, 2017)CycleGAN (ICCV, 2017)SRGAN (CVPR, 2017)StyleGAN (CVPR, 2019) GAN (NeurIPS, 2014) Generative adversarial nets m i n G m a x D …

有关‘全局唯一id‘

UUID和Snowflake的对比 当需保证全局唯一的id&#xff0c;可以选用UUID或Snowflake(及其变种) 其中UUID 不依赖于任何第三方系统&#xff0c;性能和可用性上较好&#xff1b; Snowflake生成的id具有单调递增性&#xff08;可以拿到生成时的时间戳信息&#xff09;&#xff0c;能…

深入了解MySQL中的JSON_ARRAYAGG和JSON_OBJECT函数

在MySQL数据库中&#xff0c;JSON格式的数据处理已经变得越来越常见。JSON&#xff08;JavaScript Object Notation&#xff09;是一种轻量级的数据交换格式&#xff0c;它可以用来存储和表示结构化的数据。MySQL提供了一些功能强大的JSON函数&#xff0c;其中两个关键的函数是…

HTML中name和class,id的区别和联系

在HTML中&#xff0c;name、class和id是用于标识和选择元素的属性。 区别&#xff1a; name属性&#xff1a;用于标识表单元素&#xff0c;特别是在提交表单时&#xff0c;用于识别表单数据。name属性可以在同一表单中的多个元素中重复使用。class属性&#xff1a;用于为一个…