冗余连接 代随写法的C#版本
卡码网108 与 力扣684题 总体来说一摸一样。与1971寻找图中是否存在路径很相似
因为初学 学习的代随的写法 就一直延续了没有用里扣的写法
108. 冗余连接
题目描述
有一个图,它是一棵树,他是拥有 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.
思路:我们可以从前向后遍历每一条边(因为优先让前面的边连上),边的两个节点如果不在同一个集合,就加入集合(即:同一个根节点)。关键:如果边的两个节点已经出现在同一个集合里,说明着边的两个节点已经连在一起了,再加入这条边一定就出现环了。
具体解决问题的模板还是那个模板写法 先全初始化Unifind 然后路径压缩 Find 在就是合并操作Join 和最后的判断是不是在一个集合时的操作 IsSame
代码:
using System;
public class Program {
public static void Main(string[] args) {
int N;
string[] firstLine = Console.ReadLine().Split();
N = int.Parse(firstLine[0]);
Unifind un = new Unifind(N + 1); // 注意:N + 1 是因为索引从 1 开始
for (int i = 0; i < N; i++) { //不断输入 初始化完整个 father 数组
string[] edge = Console.ReadLine().Split();
int a=int.Parse(edge[0]);
int b=int.Parse(edge[1]);
//与之前的107寻找存在的路径不同之处
if(!un.IsSame(a,b))// 不属于同一个集合时直接将a和b合并到同一个集合
{
un.Join(a,b);
}
else // 如果a和b属于同一个集合,说明添加这条边会形成环
{
// 如果它们已经在同一个集合中,则当前的边是冗余的 直接输出
Console.WriteLine(edge[0]+" "+edge[1]); //用字符串“” 加空格来表示
break;
}
}
}
}
public class Unifind {
private int[] father;
public Unifind(int N) {
father = new int[N];
for (int i = 0; i < N; ++i) {
father[i] = i; // 每个节点的父节点初始化为自己
}
}
// 查找操作(带路径压缩)
public int Find(int n) {
if (n != father[n]) {
father[n] = Find(father[n]); // 路径压缩
}
return father[n];
}
// 合并操作
public void Join(int n, int m) {
int rootN = Find(n);
int rootM = Find(m);
if (rootN != rootM) {
father[rootM] = rootN; // 将 m 的根节点指向 n 的根节点
}
}
// 判断两个节点是否属于同一个集合
public bool IsSame(int n, int m) {
return Find(n) == Find(m);
}
}