代码随想录算法训练营第56天 | 1、冗余连接,2、冗余连接II

news2024/12/28 4:13:08

目录

1、冗余连接

2、冗余连接II


1、冗余连接

题目描述

有一个图,它是一棵树,他是拥有 n 个节点(节点编号1到n)和 n - 1 条边的连通无环无向图(其实就是一个线形图),如图:

现在在这棵树上的基础上,添加一条边(依然是n个节点,但有n条边),使这个图变成了有环图,如图:

先请你找出冗余边,删除后,使该图可以重新变成一棵树。

输入描述

第一行包含一个整数 N,表示图的节点个数和边的个数。

后续 N 行,每行包含两个整数 s 和 t,表示图中 s 和 t 之间有一条边。

输出描述

输出一条可以删除的边。如果有多个答案,请删除标准输入中最后出现的那条边。

输入示例

3
1 2
2 3
1 3

输出示例

1 3

提示信息

图中的 1 2,2 3,1 3 等三条边在删除后都能使原图变为一棵合法的树。但是 1 3 由于是标准输出里最后出现的那条边,所以输出结果为 1 3

数据范围:

1 <= N <= 1000.

思路:这道题比较简单,因为是无向图,所以在并查集的基础上使用isSame函数进行判断即可。

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

int n;
vector<int> parent(1001, 0);

//初始化并查集的各结点的根
void init(){
    for(int i = 0; i < n; i ++){
        parent[i] = i;
    }
}

//找结点的根
int find(int u){
    return u == parent[u] ? u : parent[u] = find(parent[u]);//路径压缩
}

//比较两结点的根是否相同
bool isSame(int u, int v){
    u = find(u);
    v = find(v);
    return u == v;
}

//将两结点加入并查集
//存在v->u这样一条边
void join(int u, int v){
    u = find(u);
    v = find(v);
    if(u == v) return;
    parent[v] = u;
}

int main(){
    while(cin >> n){
        init();
        int node1, node2;
        for(int i = 0; i < n; i ++){
            cin >> node1 >> node2;
            if(isSame(node1, node2)){
                cout << node1 << " " << node2 << endl;
                return 0;
            }
            join(node1, node2);
        }
    }
}

2、冗余连接II

题目描述

有一种有向树,该树只有一个根节点,所有其他节点都是该根节点的后继。该树除了根节点之外的每一个节点都有且只有一个父节点,而根节点没有父节点。有向树拥有 n 个节点和 n - 1 条边。如图: 

现在有一个有向图,有向图是在有向树中的两个没有直接链接的节点中间添加一条有向边。如图:

输入一个有向图,该图由一个有着 n 个节点(节点编号 从 1 到 n),n 条边,请返回一条可以删除的边,使得删除该条边之后该有向图可以被当作一颗有向树。

输入描述

第一行输入一个整数 N,表示有向图中节点和边的个数。 

后续 N 行,每行输入两个整数 s 和 t,代表这是 s 节点连接并指向 t 节点的单向边

输出描述

输出一条可以删除的边,若有多条边可以删除,请输出标准输入中最后出现的一条边。

输入示例

3
1 2
1 3
2 3

输出示例

2 3

提示信息

在删除 2 3 后有向图可以变为一棵合法的有向树,所以输出 2 3

数据范围:

1 <= N <= 1000.

 思路:这道题相对于上面的题目来说就稍微复杂一点了。

因为是有向图,所以涉及到结点的入度有关问题。

因为只允许有一个父节点,所以当结点的入度为2时,需要删除其中一条边,这里存在两种情况;

第一种是两条边随便删除哪条都可以,那么依据题意就删除最后输入的那条;

第二种是两条边只能删除特定的边;

当然还存在一种情况,那就是没有结点的入度为2,但是自身存在自环,所以需要删除形成环的边。

这里需要注意在结点入度为2的时候,添加边的时候,遍历顺序是从后往前,这样能保证vec里面的第一个编号是标准输入的相对最后的一条边。

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

int n;
vector<int> parent(1001, 0);

//初始化各结点的根为自身
void init(){
    for(int i = 0; i < n; i ++){
        parent[i] = i;
    }
}

//寻找结点的根
int find(int u){
    return u == parent[u] ? u : parent[u] = find(parent[u]);//路径压缩
}

//判断两个结点的根是否相同
bool isSame(int u, int v){
    u = find(u);
    v = find(v);
    return u == v;
}

//将v->u这条边加入并查集
void join(int u, int v){
    u = find(u);
    v = find(v);
    if(u == v) return;
    parent[v] = u;
}


bool isTreeAfterRemove(vector<vector<int>> edge, int deleteEdge){
    init();
    for(int i = 0; i < n; i ++){
        if(i == deleteEdge) continue;//遇到删除的边就跳过
        if(isSame(edge[i][0], edge[i][1])) return false;
        join(edge[i][0], edge[i][1]);
    }
    return true;
}

void getRemove(vector<vector<int>> edge){
    init();
    for(int i = 0; i < n; i ++){
        if(isSame(edge[i][0], edge[i][1])){
            cout << edge[i][0] << " " << edge[i][1] << endl;
            return;
        }
        join(edge[i][0], edge[i][1]);
    }
}

int main(){
    while(cin >> n){
        int s, t;
        vector<int> inDegree(n + 1, 0);//计算各结点的入度
        vector<vector<int>> edge;//记录边的状态
        init();
        for(int i = 0; i < n; i ++){
            cin >> s >> t;
            inDegree[t] ++;
            edge.push_back({s, t});
        }
        vector<int> vec;//记录入度为2的边的编号
        for(int i = n - 1; i >= 0; i --){ //注意这里是倒序!!
            if(inDegree[edge[i][1]] == 2){
                vec.push_back(i);
            }
        }
        
        if(vec.size() > 0){//vec只要不为0,那么必然存在2条边可选
            if(isTreeAfterRemove(edge, vec[0])){//这里尝试删除标准输入里面的相对位置最后的边
                cout << edge[vec[0]][0] << " " << edge[vec[0]][1] << endl;
                return 0;
            }else{//上面代码没有解决问题,那么说明需要删除下面这条边
                cout << edge[vec[1]][0] << " " << edge[vec[1]][1] << endl;
                return 0;
            }
        }
        getRemove(edge);//这里是在上述vec大小为0,也就是说不存在入度为2的结点,那么此时必然存在成环的边,找到并删除
    }
}

感谢你的阅读,希望我的文章能够给你帮助,如果有帮助,麻烦点赞加收藏,或者点点关注,非常感谢。

如果有什么问题欢迎评论区讨论!

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

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

相关文章

UNI-SOP应用场景(1)- 纯前端预开发

在平时新项目开发中&#xff0c;前端小伙伴是否有这样的经历&#xff0c;hi&#xff0c;后端小伙伴们&#xff0c;系统啥时候能登录&#xff0c;啥时候能联调了&#xff0c;这是时候往往得到的回答就是&#xff0c;再等等&#xff0c;我们正在搭建系统呢&#xff0c;似曾相识的…

Marp精华总结(一)基础篇

概述 Marp是一个基于MarkDown快速编写幻灯片的工具&#xff0c;其可以基于VScode环境&#xff0c;实现MarkDown幻灯的编写和预览。Marp并不难&#xff0c;但是目前的教程还比较零散&#xff0c;而且很多细节和高级内容并没有完全展示&#xff0c;我自己是很早就体验到了Marp的…

C语言进阶之泛型列表(Generic List)

1.前言 数据结构是需要泛型的,而在C语言中实现泛型就只能去用指针魔法了,来跟我一起实现吧!所有代码经测试未发现明显bug,可放心食用. 2.代码截图展示 1.list.h 2.main.c 3.list.c 3.结语 这次分享的列表采用动态数组的方式实现,下次我会去用链表实现,两种实现方式各有优劣,希…

通信工程学习:什么是VIM虚拟化基础设施管理器

VIM:虚拟化基础设施管理器 VIM(Virtualized Infrastructure Manager)虚拟化基础设施管理器,是一种负责管理和控制虚拟化环境中所有虚拟资源的工具和系统。以下是关于VIM虚拟化基础设施管理器的详细解释: 一、定义与功能 VIM是网络功能虚拟化(NFV)架构中…

DVWA-File Inclusion(文件包含)渗透测试

概念&#xff1a; 漏洞产生原因&#xff1a; 主要是由于开发人员没有对用户输入的文件路径进行严格的过滤和验证。例如&#xff0c;如果一个 Web 应用程序接受用户输入的文件路径&#xff0c;然后使用这个路径进行文件包含&#xff0c;而没有对用户输入进行任何检查&#xff0c…

dll 研究 1

起因&#xff0c; 目的: 就是想看看 dll 里面有什么。 过程: 找到&#xff0c;打开 dumpbin 在开始菜单中搜索 “Developer Command Prompt for VS”打开&#xff0c; 然后输入 dumpbin 查看 a.dll 中 dumpbin /headers a.dll 查看头部信息dumpbin /EXPORTS a.dlldumpbin /a…

基于SSM+小程序的在线课堂微信管理系统(在线课堂1)(源码+sql脚本+视频导入教程+文档)

&#x1f449;文末查看项目功能视频演示获取源码sql脚本视频导入教程视频 1 、功能描述 &emsp1、管理员实现了首页、个人中心、用户管理、课程分类管理、课程信息管理、课程订阅管理、课程视频管理、公告栏管理、留言板管理、系统管理。 2、用户实现了首页、课程信息、公…

Web3Auth 如何工作?

Web3Auth 用作钱包基础设施&#xff0c;为去中心化应用程序 (dApp) 和区块链钱包提供增强的灵活性和安全性。在本文档中&#xff0c;我们将探索 Web3Auth 的功能&#xff0c;展示它如何为每个用户和应用程序生成唯一的加密密钥提供程序。 高级架构 Web3Auth SDK 完全存在于用…

消息号 FS215 对科目 2221010200 7333允许销项税, J1 不允许

业务场景&#xff1a; 在做发票校验时&#xff0c;报错“消息号 FS215 对科目 2221010200 7333允许销项税, J1 不允许”而且计算税额失效&#xff0c;红灯报错。 初步怀疑是税码配置问题 FTXP J1是进项税&#xff0c;但是这里维护了销项税和均一税&#xff0c;在这里删除是需…

【Python开发环境搭建】在pycharm中使用虚拟环境进行开发

每个虚拟环境都是独立的&#xff0c;打包生成的exe文件更加小巧&#xff0c;不会因为兼容性问题出现干扰 1、打开项目后&#xff0c;在右下角点击Python解释器&#xff0c;选择添加新的解释器&#xff0c;添加本地解释器 2、选择新建&#xff0c;选择合适的路径&#xff0c;取…

商业终端数据打包-android-鸿蒙——国产系统-———未来之窗行业应用跨平台架构

一、未来之窗星辰传送阵炼化炉横空出世 以下是为您编写的引言&#xff1a; 在当今的网络世界中&#xff0c;网页隔段时间就提示登录的现象令人困扰&#xff0c;严重影响了终端交互的流畅性。传统的设备 ID 识别方式存在无法动态变更数据的局限&#xff0c;轮询模式更是会使服务…

C# 利用simd比较两个文件是否相等(高性能)

主要用到两个指令集&#xff0c;CompareEqual指令与MoveMask指令&#xff0c;因为电脑cpu原因&#xff0c;我们采用Avx2。 Avx2.CompareEqual&#xff0c;比较两个Vector256<byte>向量&#xff0c;如果元素相同返回255&#xff0c;否则返回0。 Avx2.MoveMask如果Vector…

滚珠丝杠在人形机器人及线控制动和转向中大放异彩

直线驱动器用于对旋转角度不大、高负载的场景,在人形机器人中多用于四肢。直线驱动器多采取“电机+丝杠”,将旋转运动转为关节末端的直线运动,能够起到较好的支撑和承重效果,能够较好的适配应用场景的负载需求。 特斯拉人形机器人Optimus 双足、双臂采用连杆结构,连杆末端…

GS-SLAM论文阅读笔记--GEVO

前言 这篇文章看着就让人好奇。众所周知&#xff0c;高斯是一个很不错的建图方法&#xff0c;但是本文的题目居然是只用高斯进行单目VO&#xff0c;咱也不知道这是怎么个流程&#xff0c;看了一下作者来自于MIT&#xff0c;说不定是个不错的工作&#xff0c;那就具体看看吧&am…

IDEA服务启动时无法输出日志

起服务时&#xff0c;控制台啥日志也没有 解决方案&#xff1a;选择【启用调试输出】 SQL的日志无法打印 原来安装了一个Mybatis Log Free&#xff0c;用的好好的。 后来换了个项目&#xff0c;SQL执行日志就打印不出来了。 解决方案&#xff1a;换个插件&#xff0c;我换了…

Python语言把二进制转成十六进制

0 Preface/Foreword 0.1 10进制转其他进制 bin()oct()hex() 0.2 其他进制转10进制 int(, 2)int(, 8)int(, 16) 1 转换方法 1.1 方法1 先将二进制转成10进制&#xff0c;再将10进制转成16进制 decim int(00000101, 2) hexadecim hex(decim) print hexadecim 1.2 方法…

Snap AR眼镜Spectacles的技术揭秘:通往真正AR体验的道路

Snap公司自2010年成立以来&#xff0c;一直致力于探索增强现实&#xff08;AR&#xff09;技术的边界。经过多年的研发与迭代&#xff0c;Snap终于在最新一代Spectacles中实现了重大突破&#xff0c;为用户带来了前所未有的沉浸式AR体验。本文将深入探讨Spectacles的发展历程、…

【vue3】登录功能怎么实现?

无论是手机端还是pc端&#xff0c;几乎都包含登录注册方面功能&#xff0c;今天总结登录注册功能。 实现功能 注册 密码加密 登录 校验 token处理 1.环境搭建运行&#xff08;nodeexpressmongodb&#xff09; 在目录里安装express和mongoose&#xff0c;并在根目录创建server.j…

C语言编译和链接详解(通俗易懂,深入本质)

我们平时所说的程序,是指双击后就可以直接运行的程序,这样的程序被称为可执行程序(Executable Program)。在 Windows 下,可执行程序的后缀有.exe和.com(其中.exe比较常见);在类 UNIX 系统(Linux、Mac OS 等)下,可执行程序没有特定的后缀,系统根据文件的头部信息来判…

YOLOv8改进 - 注意力篇 - 引入SK网络注意力机制

一、本文介绍 作为入门性篇章&#xff0c;这里介绍了SK网络注意力在YOLOv8中的使用。包含SK原理分析&#xff0c;SK的代码、SK的使用方法、以及添加以后的yaml文件及运行记录。 二、SK原理分析 SK官方论文地址&#xff1a;SK注意力文章 SK注意力机制:SK网络中的神经元可以捕…