首页 > 其他分享 >并查集

并查集

时间:2024-04-23 13:23:35浏览次数:24  
标签:scanner int 查集 static 相似 new find

1.0 并查集概念

对于具有传递性质、联通集合的题目可以考虑并查集。

1.1 并查集模板

声明:以下模板来自于 https://xuq7bkgch1.feishu.cn/docx/CAbedNJ5KobvinxdyKgcKsrlnrd

有n个数,编号是 1~n,最开始每个数各自在一个集合中,

现在要进行 m 个操作,操作共有两种:
1. M a b,将编号为a和b的两个数所在的集合合并,如果两个数已经在同一个集合中,则忽略这个操作;

2. Q a b,询问编号为a和b的两个数是否在同一个集合中;


输入格式
第一行输入整数 n 和 m。

接下来 m 行,每行包含一个操作指令,指令为 m a b 或 q a b 中的一种。


输出格式
对于每个询问指令 Q a b,都要输出一个结果,如果a和b在同一集合内,则输出 Yes,否则输出 No
每个结果占一行。


数据范围
1 ≤n,m ≤ 105

in:

4 5
M 1 2
M 3 4
Q 1 2
Q 1 3
Q 3 4

out:

Yes
No
Yes

 

import java.util.Scanner;

public class Main {
    static int N = 100010;
    static int[] p = new int[N];
    static int n, m;

    static int find(int x) {// 没有做路径压缩
        if (p[x] != x) p[x] = find(p[x]);
        return p[x];
    }

    static void merge(int a, int b) {
        int pa = find(a), pb = find(b);
        if (pa != pb) {
            p[pa] = pb;
        }
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        n = scanner.nextInt();
        m = scanner.nextInt();
        for (int i = 1; i <= n; i++) p[i] = i;
        while (m-- > 0) {
            String ch = scanner.next();
            int a = scanner.nextInt();
            int b = scanner.nextInt();
            if (ch.equals("M")) {
                merge(a, b);
            } else {
                if (find(a) == find(b)) System.out.println("Yes");
                else System.out.println("No");
            }
        }
    }
}

离散化并查集模版

如果数据范围改为1 ≤n,m ≤ 10     应该如何处理?

import java.util.HashMap;
import java.util.Scanner;

public class Main {
  //{x,p[x]} static HashMap<Integer, Integer> p = new HashMap<>(); static int n, m; static int find(int x) { if (!p.containsKey(x)) return x; p.put(x, find(p.get(x))); return p.get(x); } static void merge(int a, int b) { int pa = find(a), pb = find(b); if (pa != pb) { p.put(pa, pb); } } public static void main(String[] args) { Scanner scanner = new Scanner(System.in); n = scanner.nextInt(); m = scanner.nextInt(); while (m-- > 0) { String ch = scanner.next(); int a = scanner.nextInt(); int b = scanner.nextInt(); if (ch.equals("M")) { merge(a, b); } else { if (find(a) == find(b)) System.out.println("Yes"); else System.out.println("No"); } } } }

20240410华为实习第一场

题目描述

小明要根据图片的相似度对图片进行分类。他通过一个N*N的矩阵M来表示任意两张图片的相似度,其中M[i][j]表示第i张图片和第j张图片的相似度。根据以下规则判断图片的相似类:

1)如果M[i][j] > 0,则认为第i张图片和第j张图片相似。
2)若A和B相似,B和C相似,但A和B不相似,则A和C间接相似,可以将A、B、C归为一类,但不考虑AC的相似度。
3)若A与所有其他图片不相似,则A被归为自己的一类,相似度总和为0。

请按照相似类的相似度总和从大到小的顺序返回每个相似类中所有图片的相似度之和。

输入
第一行一个数N,代表矩阵M中有N个图片。下面跟着N行,每行有N列数据,空格分隔(为了显示整齐,空格可能为多个),代表N个图片之间的相似度。

约束:
1. 0<N<=900
2. 0<=M[i][j]<=100,输入保证M[i][j]=0,M[i][j]=M[j][i]

3. 输入的矩阵中分隔符为1个或连续多个空格
输出
每个相似类的相似度之和。格式为:一行数字,分隔符为1个空格

样例1
输入

5
0 0 50 0 0
0 0 0 25 0
50 0 0 0 15
0 25 0 0 0
0 0 15 0 0

 

输出 

65 25
说明
把1~5看成A,B,C,D,E
矩阵显示,A和C相似度为50,C和E的相似度为15,B和D相似度为25。
划分出2个相似类,分别为 1.{A,C,E},相似度之和为65 2.{B,D},相似度之和25 排序输出相似度之和,结果为: 65 25

 

思路:并查集,遍历每个联通分量/2收集权值。

package com.coedes.union_and_find.huawei20240410;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;

/**
 * @description:https://i.cnblogs.com/posts/edit;postId=18152280#postBody
 * @author: wenLiu
 * @create: 2024/4/23 12:25
 */
public class Main {
    static final int N = 910;
    //p : parent[]  v : 存储当前节点作为父节点子树的权重
    static int[] p = new int[N], v = new int[N];

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

    static void merge(int x, int y, int val) {
        int root_x = find(x);
        int root_y = find(y);
        if (root_y != root_x) {
            p[root_x] = root_y;
            v[root_y] = v[root_x] + val;
        } else {
            v[root_y] += val;
        }
    }

    static void init(int n) {
        for (int i = 0; i < n; i++) {
            p[i] = i;
        }
    }

    public static void main(String[] args) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(reader.readLine());
        init(n);
        int[][] M = new int[n][n];
        for (int i = 0; i < n; i++) {
            String[] s = reader.readLine().split(" ");
            for (int j = 0; j < s.length; j++) {
                int inputVal = Integer.parseInt(s[j]);
                M[i][j] = inputVal;
                if (inputVal > 0) {
                    merge(i, j, inputVal);
                }
            }
        }
        ArrayList<Integer> res = new ArrayList<>();
        for (int i = 0; i < n; i++) {
            if (p[i] == i) res.add(v[i] >> 1);
        }
        Collections.sort(res);
        for (int i = res.size()-1; i >= 0; i--) {
            if (i == res.size() - 1) {
                System.out.print(res.get(i)+" ");
            } else {
                System.out.print(res.get(i));
            }
        }
    }
}

  

2024美团-人际关系

 

标签:scanner,int,查集,static,相似,new,find
From: https://www.cnblogs.com/alohablogs/p/18152280

相关文章

  • 528. 奶酪(并查集orBFS)
    题面如下:https://www.acwing.com/problem/content/530/大致思路是:合并所有连接的空洞,判断下表面的空洞和上表面的空洞是否是同一集合集合#include<iostream>#include<cstring>#include<cstdio>#include<algorithm>#include<cmath>usingnamespacestd;constintN......
  • 倍增并查集
    如果你既会倍增,又会并查集,那你一定会倍增并查集吧!link数据范围明示\(O(n^2)\)无法通过。众所周知,倍增是\(O(\logn)\)的,并查集近似\(O(n)\)的,它们结合一下不就能过了吗?先来重新考虑一下倍增的本质。倍增倍增最经典的用法是ST表。我们将一个区间拆成两个长为\(2^k\)......
  • 928. 尽量减少恶意软件的传播 II【并查集加暴力删边判断】
    题意不是很清晰:1.比如对于graph=[[1,1,0],[1,1,1],[0,1,1]],initial=[0,1]来说,可以发现结点的链接情况是0-1-2,感染源结点是0和1,若是按之前题目的要求,移除0和1都不会减少最终感染个数,但是应该返回结点0,因为其index小。但是应用此题的条件,就一定要返回结点1,因为移除结点1之......
  • P3295 [SCOI2016] 萌萌哒(倍增并查集)
    题意简述有一个长为\(n\)的数字序列\(s\),有\(q\)组限制\(l_1,r_1,l_2,r_2\)形如\(s_{l_1,\cdots,r_1}=s_{l_2\cdots,r_2}\),求满足所有限制的\(s\)的方案数,数字序列不能有前导0。\(n,q\le10^5\),保证\([l_1,r_1]\)和\([l_2,r_2]\)大小相等。分析字符之间的等量......
  • 2019年蓝桥杯省赛-修改数组(并查集)
    0.题目时间限制:1.0s内存限制:256.0MB本题总分:20分【问题描述】给定一个长度为N的数组A=[A1,A2,···AN],数组中有可能有重复出现的整数。现在小明要按以下方法将其修改为没有重复整数的数组。小明会依次修改A2,A3,···,AN。当修改Ai时,小明会检查......
  • 蓝桥杯-并查集-合根植物
    0.题目1.解析1.1并查集思路主要三大模板功能1.初始化(init)2.寻找父节点(find)3.合并(merge)我们在find中可以使用路径压缩简化运算,缩短运行时间而启发式合并则可以将运行时间压缩,由O(n)到o(logn)代码#include<bits/stdc++.h>usingnamespacestd;constintMaxn......
  • 并查集
    介绍并查集主要用于处理一些不相交集合的合并问题,一些常见的用途有求联通子图,求最小生成树的Kruskal算法和求最近公共祖先等。并查集的基本操作主要有:初始化查询合并操作初始化假设有编号为1,2,3……,n的n个元素,我们用一个数组fa[]来储存每个元素的父节点。一开始,我们先将......
  • 【学习笔记】并查集
    一、普通并查集1.定义&作用并查集是管理元素分组的算法,可以高效对元素分组(合并为一组)以及查询两个元素是否在一组。2.主要思想&实现对于每一个组,设置一个“组长”,每一次合并时只需要将其中一组的组长设为另一组的组长,查询时只需要查询组长是否相同。每一个组都可以理解......
  • 【数据结构 | 并查集】维护元素分组信息,支持高效合并集合、查询元素所在集合
    文章目录并查集概述引入并查集的实现存储方式Union-Find抽象基类两种实现思路基本实现基于QuickFind思路基于QuickUnion思路优化基于size的优化基于rank的优化find优化路径压缩路径分裂路径减半总结并查集概述并查集(DisjointSetUnion,简称并查集),也叫......
  • CF455C. Civilization-并查集
    2100分的并查集(x)link:https://codeforces.com/contest/455/problem/C给一张无向森林,有若干次操作,有两种:询问\(x\)所在树的直径合并\(x,y\)所在的连通块,使得合并后的直径最小\(n,m,q\leq3\times10^5\)处理出每个连通块的直径,考虑如何合并两个连通块?设原来的直径分别......