代码随想录算法训练day62---图论系列6《并查集2》

news/2025/2/22 19:11:36

代码随想录算法训练

—day62

文章目录

  • 代码随想录算法训练
  • 前言
  • 一、108.冗余连接
  • 二、109. 冗余连接II
  • 总结


前言

今天是算法营的第62天,希望自己能够坚持下来!
今天继续并查集系列!今日任务:
● 108.冗余连接
● 109.冗余连接II


一、108.冗余连接

卡码网题目链接
文章讲解

思路:
无向图,返回一条可以删去的边,使得结果图是一个有着N个节点的树。
如果有多个答案,则返回二维数组中最后出现的边。
那么我们就可以从前向后遍历每一条边(因为优先让前面的边连上),边的两个节点如果不在同一个集合,就加入集合。
如果边的两个节点已经出现在同一个集合里,说明着边的两个节点已经连在一起了,再加入这条边一定就出现环了。
在这里插入图片描述
在这里插入图片描述

代码如下:

#include<iostream>
#include<vector>
using namespace std;

int n;
vector<int> father = vector<int>(1001, 0);

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]);
}

bool isSame(int u, int v) {
    u = find(u);
    v = find(v);
    
    return u == v;
}

void join(int u, int v) {
    u = find(u);
    v = find(v);
    
    if (u == v) return;
    father[v] = u;
}

//遍历每一条边,把每一条边加入集合,当s,t同根的时候,说明发生了闭环,此时的s,t就是要去掉边
int main() {
    int s, t;
    cin >> n;
    init();
    
    for (int i = 1; i <= n; i++) {
        cin >> s >> t;
        if (isSame(s, t)) {
            cout << s << " " << t << endl;
            return 0;
        } else {
            join(s, t);
        }
        
    }
}

二、109. 冗余连接II

卡码网题目链接
文章讲解

思路:
与 108.冗余连接 类似,但本题是一个有向图,有向图相对要复杂一些。

如果是有向树的话,只有根节点入度为0,其他节点入度都为1
所以情况一:如果我们找到入度为2的点,那么删一条指向该节点的边就行了。
在这里插入图片描述
但 入度为2 还有一种情况,情况二,只能删特定的一条边,如图:
在这里插入图片描述综上,如果发现入度为2的节点,我们需要判断 删除哪一条边,删除后本图能成为有向树。如果是删哪个都可以,优先删顺序靠后的边。

情况三: 如果没有入度为2的点,说明 图中有环了(注意是有向环)。
在这里插入图片描述
对于情况三,删掉构成环的边就可以了。

#include<iostream>
#include<vector>
using namespace std;
int n;
vector<int> father = vector<int>(1001, 0);
 
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]);
}
 
bool isSame(int u, int v) {
    u = find(u);
    v = find(v);
    return u == v;
}
 
void join(int u, int v) {
    u = find(u);
    v = find(v);
    if (u == v) return;
    father[v] = u;
}
 
void getRemoveEdge(const vector<vector<int>>& edges) {
    init();
    for (int i = 0; i < n; i++) {
        if (isSame(edges[i][0], edges[i][1])) { //构成环了,这条就是要删的边
            cout << edges[i][0] << " " << edges[i][1] << endl;
        } else {
            join(edges[i][0], edges[i][1]);
        }
    }
}
 
bool isTreeAfterRemoveEdge(const vector<vector<int>>& edges, int deleteEdge) {
    init();
    for (int i = 0; i < n; i++) {
        if (i == deleteEdge) continue; //要删掉的边不添加到集合中
        if (isSame(edges[i][0], edges[i][1])) { //构成环了,说明不是树
            return false;
        }
        join(edges[i][0], edges[i][1]);
    }
    return true;
}
 
int main() {
    int s, t;
    vector<vector<int>> edges; //用来存放每条边
    cin >> n;
     
    vector<int> inDegree(n + 1, 0); //记录节点入度
    for (int i = 0 ;i < n; i++) {
        cin >> s >> t; //s->t
        inDegree[t]++; //t的入度+1
        edges.push_back({s,t}); //存放每条边
    }
     
    vector<int> vec; //存放入度为2的边
    //遍历每行,判断指向的节点是否入度为2,后序遍历,因为要优先删除最后出现的边
    for (int i = n - 1; i >= 0; i--) {
        if (inDegree[edges[i][1]] == 2) vec.push_back(i);
    }
     
    //情况一、情况二
    if (vec.size() > 0) {
        //放在vec里的边已经按照倒叙放了,所以这里优先删除vec[0]这条边
        if (isTreeAfterRemoveEdge(edges, vec[0])) {
            //如果删除这条边之后,是树,则这条边是答案,vec[0]是边的下标
            cout << edges[vec[0]][0] << " " << edges[vec[0]][1] << endl;
        } else {
            cout << edges[vec[1]][0] << " " << edges[vec[1]][1] << endl;
        }
        return 0;
    }
     
    //情况三,没有入度为2的节点,说明有环,找到构成环的边返回就可以了
    getRemoveEdge(edges);
    return 0;
}

总结

  • 是否有环:遍历每一条边,将边加入到集合中,如果当前遍历的边是同根isSame(u,v)=true,说明已经在集合里了,行成了环
  • 有向树的话,只有根节点入度为0,其他节点入度都为1

明天继续加油!


http://www.niftyadmin.cn/n/5862667.html

相关文章

【SPIE出版,见刊快速,EI检索稳定,浙江水利水电学院主办】2025年物理学与量子计算国际学术会议(ICPQC 2025)

2025年物理学与量子计算国际学术会议&#xff08;ICPQC 2025&#xff09;将于2025年4月18-20日在中国杭州举行。本次会议旨在汇聚全球的研究人员、学者和业界专家&#xff0c;共同探讨物理学与量子计算领域的最新进展与前沿挑战。随着量子技术的快速发展&#xff0c;其在信息处…

安装 redis 5.0.14 版本

下载 gcc rpm 包 在能上网的服务器下执行如下命令下载安装包 $> yum install --downloadonly --downloaddir/DATA/soft/temp gcc 或使用如下命令下载 # 安装yum-utils $ yum -y install yum-utils # 下载 gcc 依赖包 $ yumdownloader --resolve --destdir/rpm gcc # 参数…

项目汇报PPT转视频制作 | 有字幕和配音版

步骤 下载剪映&#xff1b; 按照稿子和PPT的节奏先进行配音的录制&#xff08;每句话都按照想要的时间间隔来控制好位置&#xff1b; 点击选中文本就会出现下面的画面 点击朗读可以选择配音的声音&#xff1b; 导出制作好的录音&#xff0c;添加到PPT中作为背景音&#xff…

open webui 部署 以及解决,首屏加载缓慢,nginx反向代理访问404,WebSocket后端服务器链接失败等问题

项目地址&#xff1a;GitHub - open-webui/open-webui: User-friendly AI Interface (Supports Ollama, OpenAI API, ...) 选择了docker部署 如果 Ollama 在您的计算机上&#xff0c;请使用以下命令 docker run -d -p 3000:8080 --add-hosthost.docker.internal:host-gatewa…

OkHttp使用和源码分析学习(二)

流程及源码分析 OkHttpClient使用过程主要涉及到OkHttpClient、Request、Response、Call、Interceptor&#xff0c;具体参考OkHttp使用。OkHttp在设计时采用门面模式&#xff0c;将整个系统复杂性隐藏&#xff0c;子系统通过OkHttpClient客户端对外提供。 流程 创建 OkHttp…

基于STM32单片机的智能蔬菜大棚温湿度监测系统设计

引言 在现代农业生产中&#xff0c;温湿度、光照强度和土壤湿度等环境因素对植物的生长起着至关重要的作用。智能蔬菜大棚正是基于这些因素&#xff0c;通过自动化控制和远程监控技术&#xff0c;实现对植物生长环境的精准管理&#xff0c;最终提升蔬菜的产量和质量。本文介绍…

Unity Excel导表工具转Lua文件

思路介绍 借助EPPlus读取Excel文件中的配置数据&#xff0c;根据指定的不同类型的数据配置规则来解析成对应的代码文本&#xff0c;将解析出的字符串内容写入到XXX.lua.txt文件中即可 EPPlus常用API //命名空间 using OfficeOpenXml;//Excel文件路径 var fileExcel new File…

论文概览 |《Urban Analytics and City Science》2023.10 Vol.50 Issue.8

本次给大家整理的是《Environment and Planning B: Urban Analytics and City Science》杂志2023年10月第50卷第8期的论文的题目和摘要&#xff0c;一共包括21篇SCI论文&#xff01; 论文1 Advances in geospatial approaches to transport networks and sustainable mobility …