代码随想录算法训练营第五十八天|108.冗余连接、109.冗余连接II

108.冗余连接

在这里插入图片描述
在这里插入图片描述

题目链接:108.冗余连接
文档讲解:代码随想录
状态:还行

思路:
并查集可以解决什么问题:两个节点是否在一个集合,也可以将两个节点添加到一个集合中。

题解:


public class Main {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt(); // 读取图中的边数
        UnionFind uf = new UnionFind(n + 1); // 初始化并查集,节点数为n+1
        for (int i = 0; i < n; i++) {
            int s = scanner.nextInt(); // 读取一条边的起点
            int t = scanner.nextInt(); // 读取一条边的终点
            if (uf.isSame(s, t)) { // 判断起点和终点是否属于同一个集合
                System.out.println(s + " " + t); // 如果是同一个集合,输出这条冗余边
                return; // 结束程序
            }
            uf.join(s, t); // 将起点和终点加入同一个集合
        }
    }

    static class UnionFind {
        private int n; // 节点数
        private int[] father; // 父节点数组

        public UnionFind(int n) {
            this.n = n; // 初始化节点数
            father = new int[n]; // 初始化父节点数组
            init(); // 初始化父节点数组
        }

        private void init() {
            for (int i = 0; i < n; i++) {
                father[i] = i; // 将每个节点的父节点初始化为自身
            }
        }

        private int find(int u) {
            // 查找节点u的根节点,并进行路径压缩
            return father[u] == u ? u : (father[u] = find(father[u]));
        }

        public void join(int u, int v) {
            // 将节点u和节点v的集合合并
            u = find(u); // 找到节点u的根节点
            v = find(v); // 找到节点v的根节点
            if (u != v) {
                father[v] = u; // 将节点v的根节点设置为u
            }
        }

        public boolean isSame(int u, int v) {
            // 判断节点u和节点v是否属于同一个集合
            return find(u) == find(v);
        }
    }
}

109.冗余连接II

题目链接:109.冗余连接II
文档讲解:代码随想录
状态:不会

思路:

可能情况
1.存在有环边
在这里插入图片描述
2.存在入度为2的顶点
在这里插入图片描述
3.同时存在有环边和入度为2的顶点
在这里插入图片描述

解题思路可以分为三种情况:

节点的入度为2:如果一个节点有两条入边,删除其中一条边会使得图变成树。
构成环的边:如果没有节点的入度为2,那么一定有一个环。删除环中的任意一条边会使得图变成树。

public class Main {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt(); // 读取图中的节点数
        int[][] edges = new int[n][2]; // 存储每条边的起点和终点
        int[] inDegree = new int[n + 1]; // 记录每个节点的入度
        UnionFind uf = new UnionFind(n + 1); // 初始化并查集,节点数为n+1
        for (int i = 0; i < n; i++) {
            int s = scanner.nextInt(); // 读取一条边的起点
            int t = scanner.nextInt(); // 读取一条边的终点
            inDegree[t]++; // 终点节点的入度加1
            edges[i][0] = s;
            edges[i][1] = t;
        }
        List<Integer> vec = new ArrayList<>(); // 记录入度为2的边(如果有的话就两条边)
        // 找入度为2的节点所对应的边,注意要倒序,因为优先删除最后出现的一条边
        for (int i = n - 1; i >= 0; i--) {
            if (inDegree[edges[i][1]] == 2) {
                vec.add(i);
            }
        }
        if (!vec.isEmpty()) {
            // 放在vec里的边已经按照倒叙放的,所以这里就优先删vec.get(0)这条边
            if (uf.isTreeAfterRemoveEdge(edges, vec.get(0), n)) {
                System.out.println(edges[vec.get(0)][0] + " " + edges[vec.get(0)][1]);
            } else {
                System.out.println(edges[vec.get(1)][0] + " " + edges[vec.get(1)][1]);
            }
            return;
        }
        // 处理情况三
        // 明确没有入度为2的情况,那么一定有有向环,找到构成环的边返回就可以了
        uf.getRemoveEdge(edges, n);
    }

    // 并查集类
    static class UnionFind {
        private int n; // 节点数
        private int[] father; // 父节点数组

        public UnionFind(int n) {
            this.n = n; // 初始化节点数
            father = new int[n]; // 初始化父节点数组
            init(); // 初始化父节点数组
        }

        private void init() {
            // 将每个节点的父节点初始化为自身
            for (int i = 0; i < n; i++) {
                father[i] = i;
            }
        }

        // 查找节点u的根节点,并进行路径压缩
        private int find(int u) {
            if (u != father[u]) {
                father[u] = find(father[u]);
            }
            return father[u];
        }

        // 将节点u和节点v的集合合并
        public void join(int u, int v) {
            u = find(u); // 找到节点u的根节点
            v = find(v); // 找到节点v的根节点
            if (u != v) {
                father[v] = u; // 将节点v的根节点设置为u
            }
        }

        // 判断节点u和节点v是否属于同一个集合
        public boolean isSame(int u, int v) {
            return find(u) == find(v);
        }

        // 在有向图里找到删除的那条边,使其变成树
        void getRemoveEdge(int[][] edges, int n) {
            init(); // 初始化并查集
            for (int i = 0; i < n; i++) { // 遍历所有的边
                if (isSame(edges[i][0], edges[i][1])) { // 构成有向环了,就是要删除的边
                    System.out.println(edges[i][0] + " " + edges[i][1]);
                    return;
                } else {
                    join(edges[i][0], edges[i][1]);
                }
            }
        }

        // 删一条边之后判断是不是树
        boolean isTreeAfterRemoveEdge(int[][] edges, int deleteEdge, int n) {
            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;
        }
    }
}

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-19 19:36:02       67 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-19 19:36:02       71 阅读
  3. 在Django里面运行非项目文件

    2024-07-19 19:36:02       58 阅读
  4. Python语言-面向对象

    2024-07-19 19:36:02       69 阅读

热门阅读

  1. ArkTS语法---运算符及语句

    2024-07-19 19:36:02       22 阅读
  2. Python_封装和继承

    2024-07-19 19:36:02       16 阅读
  3. SQL Server 和 MySQL 的主要区别

    2024-07-19 19:36:02       20 阅读
  4. 益铭祥元宇宙

    2024-07-19 19:36:02       19 阅读
  5. 计算机视觉7 kag比赛

    2024-07-19 19:36:02       19 阅读
  6. 《管理表格系统》开发心得

    2024-07-19 19:36:02       21 阅读
  7. gdb 的常用指令

    2024-07-19 19:36:02       20 阅读
  8. 矩形加矩形求和

    2024-07-19 19:36:02       20 阅读
  9. TCP协议

    TCP协议

    2024-07-19 19:36:02      19 阅读
  10. 深入探讨:Node.js、Vue、SSH服务与SSH免密登录

    2024-07-19 19:36:02       21 阅读
  11. GitHub每日最火火火项目(7.18)

    2024-07-19 19:36:02       18 阅读
  12. 微服务常用的中间件有哪些?都有什么用途?

    2024-07-19 19:36:02       18 阅读
  13. 逆向工程四个抽象层次-系统架构师(三十)

    2024-07-19 19:36:02       21 阅读