卡码网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);
    }
}

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部