并查集与拓扑排序(题目JAVA)

并查集与拓扑排序

并查集就是开一个数组存每个节点的父节点,然后查找和并两个方法。遇到的题不一样思考方式也不一样。可能就是改变并的方式。并查集是一种用于管理元素所属集合的数据结构,其最终的状态为一个森林。森林中的每棵树表示一个集合,树中的节点表示对应集合中的元素。
拓扑排序(Topological sorting)要解决的问题是如何给一个有向无环图的所有节点排序。

1.蓝桥幼儿园(模版题)

java 复制代码
package com.js.datastructure.recursion.蓝桥.国特训练营.并查集;

import java.util.Scanner;

public class 蓝桥幼儿园 {
    static int [] pa;
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        int n = scanner.nextInt();
        int m = scanner.nextInt();
        pa = new int[n+1];

        //建立父节点数组
        for (int i = 1; i < n+1; i++) {
            pa[i] = i;
        }

        for (int i = 0; i < m; i++) {
            int op = scanner.nextInt();
            int x = scanner.nextInt();
            int y = scanner.nextInt();
            if(op == 1){
                union(x,y);
            }else {
                if(x == y){
                    System.out.println("YES");
                }else {
                    int x_pa = find(x);
                    int y_pa = find(y);
                    if(x_pa == y_pa){
                        System.out.println("YES");
                    }else {
                        System.out.println("NO");
                    }
                }
            }
        }

    }

    static int find(int x){
        if(pa[x] == x){
            return x;
        }
        pa[x] = find(pa[x]);
        return pa[x];
    }

    static void union(int x, int y){
        int x_pa = find(x);
        int y_pa = find(y);

        if(x_pa != y_pa){
            pa[y_pa] = x_pa;
        }
    }
}

2.关押罪犯


这个题有点不太好理解,就是并的方式不太一样,查的话都一样。

互不交集的一对一对没有影响,有影响的是有交集的,

比如例子

1 2

3 4

1 3

2 3

1 4

2 4

这是按照影响排序后的,前两个如果此时就直接确定在那个监狱,第三个就就会受影响,所以需要存的是每次只需要知道这两个不在一个监狱,后面可以把监狱合并,这是这个题的并。

java 复制代码
package com.js.datastructure.recursion.蓝桥.国特训练营.并查集;

import java.util.*;

public class 关押罪犯 {
    static int pa[];
    static class Edge{
        int a;
        int b;
        int c;
        public Edge(int a,int b,int c){
            this.a = a;
            this.b = b;
            this.c = c;
        }
    }

    static int find(int x){
        if(pa[x] == x){
            return x;
        }
        pa[x] = find(pa[x]);
        return pa[x];
    }
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int m = scanner.nextInt();

        pa = new int[2*n+2];
        for (int i = 0; i < pa.length; i++) {
            pa[i] = i;
        }
        ArrayList<Edge> dd = new ArrayList<>();
        for (int i = 0; i < m; i++) {
            dd.add(new Edge(scanner.nextInt(),scanner.nextInt(),scanner.nextInt()));
        }
        Collections.sort(dd,(Edge o1,Edge o2) -> Long.compare(o2.c,o1.c));
        for (Edge ddd: dd){
            int a = ddd.a;
            int b = ddd.b;
            int c = ddd.c;

            int pa_a = find(a);
            int pa_b = find(b);

            if(pa_a == pa_b){
                System.out.println(c);
                return;
            }
            pa[pa_a] = find(b+n);
            pa[pa_b] = find(a+n);

        }
        System.out.println(0);

    }
}

3.发现环(拓扑排序)


这个题利用链式前向星存边,然后依次去掉入度为1的边,得到最后入度为2的点就是环,然后利用ArrayList存这些点,排序输出。

java 复制代码
package com.js.datastructure.recursion.蓝桥.国特训练营.并查集;

import java.util.*;

public class 发现环 {

    static int [] pa;
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        int n = scanner.nextInt();

        //记录入度
        //存储边
        ArrayList<Integer>[] ed = new ArrayList[n+1];
        //初始化
        for (int i = 0; i < n + 1; i++) {
            ed[i] = new ArrayList<>();
        }

        int[] de = new int[n+1];

        for (int i = 0; i < n; i++) {
            int a = scanner.nextInt();
            int b = scanner.nextInt();
            //两边的入度都增加
            de[a]++;
            de[b]++;
            ed[a].add(b);
            ed[b].add(a);
        }

        //队列来优化入度为1的节点
        Deque<Integer> qu = new ArrayDeque<>();
        for (int i = 1; i < n+1; i++) {
            if(de[i] == 1){
                qu.offer(i);
            }
        }

        while (!qu.isEmpty()){
            int t = qu.pollFirst();
            de[t]--;
            for (int z : ed[t]){
                de[z]--;
                if(de[z] == 1){
                    qu.addLast(z);
                }
            }
        }


        ArrayList<Integer> doo = new ArrayList<>();
        for (int i = 1; i < n+1; i++) {
            if(de[i] == 2){
                doo.add(i);
            }
        }
        Collections.sort(doo);
        for (int dooo:doo) {
            System.out.print(dooo + " ");
        }

    }
}

4.最小字典序排列(拓扑排序)


这个题加了一个最小的限制条件,在使用队列的时候使用优先队列。

java 复制代码
package com.js.datastructure.recursion.蓝桥.国特训练营.并查集;

import java.util.ArrayList;
import java.util.PriorityQueue;
import java.util.Scanner;

public class 最小字典序排列 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        int n = scanner.nextInt();
        int m = scanner.nextInt();

        //就是拓扑排序,有向无环图的排序。
        //链式前向星存储边,数组存入度出度。
        int[] de = new int[n+1];
        ArrayList<Integer> [] ar = new ArrayList[n+1];
        //初始化
        for (int i = 0; i < n + 1; i++) {
            ar[i] = new ArrayList();
        }

        for (int i = 0; i < m; i++) {
            int a = scanner.nextInt();
            int b = scanner.nextInt();
            de[b]++;
            ar[a].add(b);
        }

        //删除掉入度为0的点,依次进行,因为要求字典序最小所以用优先队列,默认小根堆
        PriorityQueue<Integer> qu = new PriorityQueue<>();
        for (int i = 1; i < n+1; i++) {
            if(de[i] == 0){
                qu.offer(i);
            }
        }

        ArrayList<Integer> dd = new ArrayList<>();
        while (!qu.isEmpty()){
            int t = qu.poll();
            dd.add(t);
            for (int z : ar[t]){
                de[z]--;
                if(de[z] == 0){
                    qu.add(z);
                }
            }
        }

        for (int i = 1; i < n + 1; i++) {
            if(de[i] != 0){
                System.out.println(-1);
                return;
            }
        }
        for (int z : dd){
            System.out.print(z + " ");
        }

    }
}
相关推荐
Noii.4 分钟前
Spring Boot初级概念及自动配置原理
java·spring boot·后端
探索java11 分钟前
Tomcat Server 组件原理
java·后端·tomcat
勿在浮沙筑高台11 分钟前
无法获取实体类com.example.springdemo2.entity.po.UserPO对应的表名!
java·spring boot·mybatis
程高兴13 分钟前
遗传算法求解冷链路径优化问题matlab代码
开发语言·人工智能·matlab
wow_DG17 分钟前
【C++✨】多种 C++ 解法固定宽度右对齐输出(每个数占 8 列)
开发语言·c++·算法
用户83562907805131 分钟前
Java使用Spire.Doc实现Word转PDF:格式精准的自动化解决方案
java
陆小叁43 分钟前
基于Flink CDC实现联系人与标签数据实时同步至ES的实践
java·elasticsearch·flink
CHEN5_021 小时前
【Java基础】反射,注解,异常,Java8新特性,object类-详细介绍
java·开发语言
Cx330❀1 小时前
【数据结构初阶】--排序(四):归并排序
c语言·开发语言·数据结构·算法·排序算法
云间月13141 小时前
飞算JavaAI智慧文旅场景实践:从景区管理到游客服务的全链路系统搭建
java·开发语言