首页 > 试题广场 >

朋友圈(后端开发卷)

[编程题]朋友圈(后端开发卷)
  • 热度指数:8055 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
现在有 105 个用户,编号为 1- 105,现在已知有 m 对关系,每一对关系给你两个数 x 和 y ,代表编号为 x 的用户和编号为 y 的用户是在一个圈子中,例如: A 和 B 在一个圈子中, B 和 C 在一个圈子中,那么 A , B , C 就在一个圈子中。现在想知道最多的一个圈子内有多少个用户。

数据范围:
进阶:空间复杂度 ,时间复杂度

输入描述:
第一行输入一个整数T,接下来有T组测试数据。
对于每一组测试数据:第一行输入1个整数n,代表有n对关系。
接下来n行,每一行输入两个数x和y,代表编号为x和编号为y的用户在同一个圈子里。
1 ≤ T ≤ 10
1 ≤ n ≤ 2*106
1 ≤ x, y ≤ 105


输出描述:
对于每组数据,输出一个答案代表一个圈子内的最多人数
示例1

输入

2
4
1 2
3 4
5 6
1 6
4
1 2
3 4
5 6
7 8

输出

4
2
一看到这种求连通关系的就要想到使用并查集,为了进一步优化时间复杂度,记得在find方法中添加路径压缩。
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;


class UnionFind {
    public static int[] parent = new int[10000001];
    public static int[] personNums = new int[10000001];
    public UnionFind(){
        for(int i = 1; i <= 10000000; i++){
            parent[i] = i;
            personNums[i] = 1;
        }
    }
    
    public int find(int x) {
        while(x != parent[x]){
            parent[x] = parent[parent[x]];    // 路径压缩
            x = parent[x];
        }
        return x;
    }
    
    public void union(int x, int y){
        int rootX = find(x);
        int rootY = find(y);
        if(rootX == rootY) return;
        parent[rootY] = rootX;
        personNums[rootX] += personNums[rootY];
    }
}


public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int T = Integer.parseInt(br.readLine());
        while(T -- > 0){
            int n = Integer.parseInt(br.readLine());
            UnionFind uf = new UnionFind();
            for(int i = 0; i < n; i++){
                String[] params = br.readLine().trim().split(" ");
                int x = Integer.parseInt(params[0]);
                int y = Integer.parseInt(params[1]);
                uf.union(x, y);
            }
            int max = 0;
            for(int i = 1; i < uf.personNums.length; i++)
                max = Math.max(max, uf.personNums[i]);
            System.out.println(max);
        }
    }
}

编辑于 2021-07-22 16:11:31 回复(7)
一开始碰到这题没思路,看了一下各位前辈的回答了解到这是一个典型的并查集问题,详情可参考算法学习笔记(1) : 并查集 - 知乎 (zhihu.com)
#include <iostream>
#include <unordered_map>

using namespace std;

unordered_map<int, int> fa;  //用fa来存储父节点
unordered_map<int, int> cnt;  //用cnt来存储节点的子节点数量

int find(int x)  //寻找父节点
{
    if (fa.find(x) == fa.end()) {  //fa[x]尚未存在表中时
        fa[x] = x;  //将fa[x]的父节点设置为自己
        cnt[x] = 0;
    }
    if (x == fa[x]) {
        return x;
    }
    return fa[x] = find(fa[x]);  //将x的根节点设置为父节点(路径压缩),并返回根节点
}

void Union(int x, int y)  //合并
{
    int fx = find(x);  //fx为x的父节点
    int fy = find(y);  //fy为y的父节点
    fa[fx] = fy;  //将fx的父节点设为fy
}

int main()
{
    int T;
    cin >> T;
    while (T--)
    {
        int n;
        cin >> n;
        while (n--)
        {
            int x, y;
            cin >> x >> y;
            Union(x, y);
        }
        int ans = 0;  //每个节点子节点数至少为1(其自身),故将初始ans设置为0用于后续比较
        for (unordered_map<int,int>::iterator it=fa.begin();it!=fa.end(); it++)
        {
            int fi = find(it->second);
            cnt[fi]++;  //每到节点i就往其根节点cnt[]+1
            if (cnt[fi] > ans)
                ans = cnt[fi];
        }
        cout << ans << endl;
        fa.clear();
        cnt.clear();
    }
    return 0;
}

编辑于 2021-08-06 10:55:29 回复(10)
//  邻接表 + dfs
#include<iostream>
#include<vector>
using namespace std;
int cnt,ans;
int v[100001];
vector<int>a[100001];
void dfs(int x)
{
    int i,num;
    v[x]=1; cnt++;
    for(i=0;i<a[x].size();i++)
    {
        num=a[x][i];
        if(v[num]==0)dfs(num);
    }
}
int main()
{
    int i,k,n,x,y,T;
    scanf("%d",&T);
    for(i=0;i<T;i++)
    {
        scanf("%d",&n);
        for(k=1;k<=1e5;k++)
        {
            v[k]=0;
            a[k].clear();
        }
        for(k=1;k<=n;k++)
        {
            scanf("%d %d",&x,&y);
            a[x].push_back(y);
            a[y].push_back(x);
        }
        ans=0;
        for(k=1;k<=1e5;k++)
        {
            cnt=0;
            dfs(k);
            ans=max(ans,cnt);
        }
        printf("%d\n",ans);
    }
    return 0;
}

发表于 2022-02-10 12:46:12 回复(0)

使用并查集,并添加路径压缩。关于并查集和路径压缩的讲解见并查集

详细注释代码如下:

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

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int t = sc.nextInt(); // t组数据
        for (int i = 0; i < t; i++) {
            int n = sc.nextInt(); // n对关系
            HashMap<Integer,Integer> map = new HashMap<>(); // 用户数字 到 数组位置 的映射
            int[] check = new int[n * 2]; // 并查集数组(n对,最多 n * 2 个用户)

            for (int j = 0; j < n * 2; j++) { // 初始化并查集,指向自己
                check[j] = j;
            }

            for (int j = 0; j < n; j++) { // 建立并查集
                int a = sc.nextInt(); // 读入用户对
                int b = sc.nextInt();
                int x = map.getOrDefault(a, map.size()); // 找到映射
                map.put(a, x);
                int y = map.getOrDefault(b, map.size());
                map.put(b, y);

                if (find(check, x) != x && find(check, y) != y) { // 当都有根,从根部联通两并查集,能减少find的次数
                    check[find(check, x)] = find(check, y); // (连接方式未优化)
                } else if (find(check, x) != x) { // 只有一方有根,另一方直接连到根;都没根时一样
                    check[y] = find(check, x);
                } else {
                    check[x] = find(check, y);
                }
            }

            HashMap<Integer,Integer> res = new HashMap<>(); // 并查集根 和 并查集节点个数 的映射
            for (int j = 0; j < n * 2; j++) { // 遍历并查集
                int k = find(check, j); // 找到当前节点的根
                res.put(k, res.getOrDefault(k, 0) + 1); // 节点个数加一
            }

            int max = 0;
            for (Integer value : res.values()) { // 遍历各个并查集的节点个数,找出最大者
                max = Math.max(max, value);
            }

            System.out.println(max); // 打印
        }
    }

    // 查找并查集的根
    private static int find(int[] check, Integer i) {
        if (check[i] != i) { // 当前节点非根
            check[i] = find(check, check[i]); // 当前节点指向根(路径压缩)
        }
        return check[i]; // 返回根
    }
}
发表于 2021-08-17 19:48:43 回复(0)
抛砖引玉,给个python的解决方案。参照了前面大佬的C++方案,结果是对的,方案不一定最优,希望大佬们看到了可以提出优化的建议。
"""使用并查集解题"""
""" 运行时间: 2834ms
    占用内存: 14236KB """
class UnionFind():
    def __init__(self, **kwargs):
        """构造函数"""
        self.fa = [i for i in range(int(1e5+1))]    #存储每个数据的根节点
        self.num = [1] * int(1e5+1)     #存储根节点的子节点数目
        self.max_num = 1
    
    def find(self, p):
        """查找根节点"""
        if self.fa[p] == p:
            return p
        self.fa[p] = self.find(self.fa[p])#把父节点的根节点当作父节点
        return self.fa[p] #返回父节点,此时父节点就是根节点

    def merge(self, p, q):
        """连通p,q 让q指向p"""
        proot = self.find(p)
        qroot = self.find(q)
        if proot != qroot:
            self.fa[qroot] = proot
            self.num[proot] += self.num[qroot]
            self.max_num = max(self.max_num, self.num[proot])
    
    def get_max(self):
        return self.max_num

    def reset(self):
        self.fa = [i for i in range(int(1e5+1))]
        self.num = [1] * int(1e5+1)
        self.max_num = 1


T = int(input().strip())
UF = UnionFind()

for i in range(T):
    # print(f'第{i+1}组测试数据')
    UF.reset()
    n = int(input().strip())
    ii = 0
    while ii < n:
        p, q = map(int, input().split())
        UF.merge(p, q)
        ii += 1
    print(UF.get_max())


发表于 2022-03-03 15:49:00 回复(0)
开始的时候已经想到是并查集的问题了,但还是想先用HashSet暴力解看能不能快点过,但直接超时。并查集的原理和树的概念脱不开关系,树的传统储存方式通常是数组,但这个问题中,给的数是没有所谓的前后关系的,不可能最大的数是多少就创建多大的数组以求下标能表示到。所以可以考虑使用Map来代替数组,实际上并查集的做法跟Map相似,都是Key-Value的思想。
importjava.util.*;
importjava.io.*;
importjava.lang.Math;

public class Main {
    public static void main(String[] args) {
        Scanner cin=new Scanner(new BufferedInputStream(System.in));
        int t=cin.nextInt();
        int[] res=new int[t];
        for (int i = 0; i < t; ++i) {
            int n = cin.nextInt();
            int[][] relationships = new int[n][2];
            Set<Integer> UFS=new HashSet<>();    //收集这一组中出现过的元素,用于下面建立并查集
            for (int j = 0; j < n; ++j) { //自定义格式化每一组的关系
                relationships[j][0] = cin.nextInt();
                relationships[j][1] = cin.nextInt();
                UFS.add(relationships[j][0]);
                UFS.add(relationships[j][1]);
            }
            res[i]=maxCircle(relationships,UFS);    //计算这一组中最大圈子的数量
        }
        for (int re : res) {
            System.out.println(re);
        }
        cin.close();
    }

    private static int maxCircle(int[][] relationships,Set<Integer> UFS) {
        Map<Integer,Integer> ufs=new HashMap<>();
        for (Integer uf : UFS)    //初始化并查集
            ufs.put(uf,-1);
        for (int[] relationship : relationships)
            ufsUnion(ufs,relationship[0],relationship[1]);    //根据关系调整并查集
        int min = 0;
        for (Integer uf : UFS)
            min=Math.min(ufs.get(uf),min);
        return (-1)*min;
    }

    private static void ufsUnion(Map<Integer, Integer> ufs, int a, int b) {
        int root1=ufsFind(ufs,a);
        int root2=ufsFind(ufs,b);
        if (root1==root2) return;
        int temp1=ufs.get(root1);
        int temp2=ufs.get(root2);
                //路径压缩,让小树并到大树下,尽量减少树的高度
        if (temp1<temp2) {
            ufs.put(root2,root1);
            ufs.put(root1,temp1+temp2);
        }
        else {
            ufs.put(root1,root2);
            ufs.put(root2,temp1+temp2);
        }
    }

    private static int ufsFind(Map<Integer,Integer> ufs,int a) {
        int temp=a;
        while (ufs.get(temp)>0)
            temp=ufs.get(temp);
        return temp;
    }
}


编辑于 2022-01-31 23:54:06 回复(0)
沙口解法,dfs省份问题警告
#include <bits/stdc++.h>

using namespace std;

int total_t, n;


int NumofLargestGroup(vector<int>* mat, int n)
{
    if(!n)
        return n;
    vector<bool> visited(10000005, false);
    int ans = 0;
    
    stack<int> s;
    
    for(int i = 1; i <= 10000000; ++i)
    {
        if(visited[i] || mat[i].empty())
            continue;
        s.push(i);
        
        int cur_ans = 0;
        while(!s.empty())
        {
            int cur = s.top();
            s.pop();
            
            if(visited[cur])
                continue;
            visited[cur] = true;
            ++cur_ans;
            for(const auto& fr : mat[cur])
            {
                
                //cout << "cur " << cur <<" fr " << fr << endl;
                if(visited[fr])
                    continue;
                s.push(fr);
            }
        }
        ans = max(ans, cur_ans);
            
    }
    return ans;
}


int main()
{
    ios::sync_with_stdio(false), cin.tie(0);
    cin >> total_t;
    
    while(total_t--)
    {
        vector<int> mat[10000005];
        
        
        cin >> n;
        int a, b;
        for(int i = 1; i <= n; ++i)
        {
            cin >> a >> b;
            
            mat[a].push_back(b);
            mat[b].push_back(a);
        }
        
        cout << NumofLargestGroup(mat, n) << endl;
    }
}

发表于 2021-07-22 16:12:57 回复(0)
咋都是并查集,只有我是纯纯地模拟吗,结果也过了
public class Solution {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int graph_nums = sc.nextInt();
        int T = 0;
        while (T < graph_nums){
            LinkedHashSet<edge> edges = new LinkedHashSet<>();
            int edges_nums = sc.nextInt();
            for (int i = 0; i < edges_nums; i++) {
                 edge edge = new edge(sc.nextInt(),sc.nextInt());
                 edges.add(edge);
            }
            int pyq = pyq(edges);
            System.out.println(pyq);
            T++;
        }
        sc.close();
    }


    //求最大连通分量
    public static int pyq(LinkedHashSet<edge> edges){
        // 1. 构建邻接表
        Map<Integer, List<Integer>> adjacencyList = new HashMap<>();
        for (edge e : edges) {
            adjacencyList.putIfAbsent(e.node1, new ArrayList<>());
            adjacencyList.putIfAbsent(e.node2, new ArrayList<>());
            adjacencyList.get(e.node1).add(e.node2);
            adjacencyList.get(e.node2).add(e.node1);
        }

        // 2. 遍历每个连通分量,记录最大值
        int maxComponentSize = 0;
        Set<Integer> visited = new HashSet<>();
        for (int node : adjacencyList.keySet()) {
            if (!visited.contains(node)) {
                int componentSize = dfs(adjacencyList, node, visited);
                maxComponentSize = Math.max(maxComponentSize, componentSize);
            }
        }

        return maxComponentSize;
    }

    private static int dfs(Map<Integer, List<Integer>> adjacencyList, int node, Set<Integer> visited) {
        visited.add(node);
        int componentSize = 1;
        for (int neighbor : adjacencyList.getOrDefault(node, new ArrayList<>())) {
            if (!visited.contains(neighbor)) {
                componentSize += dfs(adjacencyList, neighbor, visited);
            }
        }
        return componentSize;
    }

}

class edge{
    int node1,node2;

    edge(int node1,int node2){
        this.node1 = node1;
        this.node2 = node2;
    }

    public boolean equals(edge e) {
        if ((e.node1 == this.node1 && e.node2 == this.node2) ||
                (e.node1 == this.node2 && e.node2 == this.node1)){
            return true;
        }
        return false;
    }
}


发表于 2023-04-03 15:24:46 回复(0)
给一个chatgpt的答案:

可以使用并查集(Union-Find)来解决此问题。首先将所有用户看作一个单独的圈子,然后遍历所有关系对,将它们所在的圈子合并起来。最终,统计每个圈子的大小并找到最大值即可。

以下是Python代码的示例实现:

class UnionFind:
    def __init__(self, n):
        self.parent = list(range(n))
        self.size = [1] * n
    
    def find(self, x):
        if self.parent[x] != x:
            self.parent[x] = self.find(self.parent[x])
        return self.parent[x]
    
    def union(self, x, y):
        root_x, root_y = self.find(x), self.find(y)
        if root_x == root_y:
            return
        if self.size[root_x] < self.size[root_y]:
            root_x, root_y = root_y, root_x
        self.parent[root_y] = root_x
        self.size[root_x] += self.size[root_y]

def max_circle(m):
    uf = UnionFind(105)
    for x, y in m:
        uf.union(x-1, y-1)
    return max(uf.size)

# Example usage:
m = [(1, 2), (2, 3), (4, 5), (6, 7), (7, 8), (9, 10), (100, 101)]
max_size = max_circle(m)
print(max_size) # Output: 4

其中,UnionFind类实现了并查集,其中parent数组用于记录每个节点的父节点,size数组用于记录每个圈子的大小。find方法实现了路径压缩,使查找操作的时间复杂度接近常数。union方法实现了按秩合并和路径压缩,使合并操作的时间复杂度接近常数。

max_circle函数使用UnionFind类来处理关系对,然后找到最大圈子的大小并返回。

================================
感谢chatgpt,可以取代我了

发表于 2023-03-26 16:58:25 回复(0)
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

const int MAX_N = 1e5 + 5;
int parent[MAX_N];
int sz[MAX_N];

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

void merge(int x, int y) {
    int px = find(x);
    int py = find(y);
    if (px == py) {
        return;
    }
    parent[py] = px;
    sz[px] += sz[py];
}


int main() {
    cin.tie(0);
    cout.tie(0);
    ios::sync_with_stdio(0);
    int t;
    cin >> t;
    while (t--) {
        int m;
        cin >> m;
        unordered_set<int> set;
        for (int i = 0; i < MAX_N; i++) {
            sz[i] = 1;
            parent[i] = i;
        }
        for (int i = 0; i < m; i++) {
            int x, y;
            cin >> x >> y;
            set.insert(x);
            set.insert(y);
            merge(x, y);
        }
        int ans = 0;
        for (auto x : set) {
            ans = max(ans, sz[find(x)]);
        }
        cout << ans << endl;
    }

    return 0;
}

发表于 2023-01-16 19:21:41 回复(0)
#参考https://oi-wiki.org/ds/dsu/
class Dsu:
    def __init__(self,size):
        self.pa = list(range(size))
        self.size = [1]*size
        self.max_size=1
    def find(self,x): #沿着树向上找到x的根节点,并将查询过程中经过的每个元素都归到根节点(路径压缩)
        if self.pa[x]!=x:
            self.pa[x] = self.find(self.pa[x])
        return self.pa[x]
    def union(self,x,y):# 将x的根节点接到y,
        #启发式合并,将小的树合并到大的树
        x,y = self.find(x),self.find(y)
        if x==y: return
        if self.size[x]<self.size[y]:
            x,y=y,x
        self.pa[y]=x
        self.size[x]+=self.size[y]
        if self.size[x]>self.max_size:
            self.max_size=self.size[x]
            
        
while True:
    try:
        T=int(input())
        for _ in range(T):
            n = int(input())
            dsu = Dsu(100000+1)
            
            for _ in range(n):
                x,y=list(map(int,input().split()))
                dsu.union(x,y)
                
            print(dsu.max_size)
            del dsu
        
    except: break

发表于 2022-10-15 22:24:18 回复(0)
# 深度优先算法
t=int(input())
from collections import defaultdict
import sys  # 导入sys模块
sys.setrecursionlimit(30000)
def rec(num):
    if dic.get(num):
        return dic.get(num)
    visitd.add(num)
    find_count=1
    for p in edge[num]:
        if p not in visitd:
            find_count+=rec(p)
    dic[num]=find_count
    return dic[num]
for i in range(t):
    edge=defaultdict(list)
    n,nums,dic=int(input()),set(),{}
    for j in range(n):
        x,y=[m for m in input().split()]
        nums.add(x)
        nums.add(y)
        edge[x].append(y)
        edge[y].append(x)
    visitd,max_count=set(),2
    for q in nums:
        if q not in visitd and (len(nums)-len(visitd))>max_count:
            tem=rec(q)
            max_count=max(max_count,tem)
    print(max_count)

#广度优先算法
t=int(input())
from collections import defaultdict
for i in range(t):
    edge,max_count=defaultdict(list),2
    n,nums,visited=int(input()),set(),set()
    for j in range(n):
        x,y=[m for m in input().split()]
        nums.add(x)
        nums.add(y)
        edge[x].append(y)
        edge[y].append(x)
    for i in nums:
        if i not in visited:
            count,stack=1,[i]
            visited.add(i)
            while stack:
                cur=stack.pop()
                for j in edge[cur]:
                    if j not in visited:
                        visited.add(j)
                        stack.append(j)
                        count+=1
            max_count=max(max_count,count)
    print(max_count)   
编辑于 2022-09-06 17:36:21 回复(0)
import java.util.*;

public class Main {
    /*
        整体背景就是一堆孩子 认爹 
        然后看哪个爹孩子最多(还要加上老爹)
      */
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        //一共几组数据
        for (int i = 0; i < n; i++) {
            //找自己的爹节点 如果parent中不存在自己 那么说明自己没有爹节点
            //自己就是自己的爹
    
            Map<Integer, Integer> parent = new HashMap<Integer, Integer>();
            
            //哪个爹有多少个孩子  key是爹  value是孩子的数量
            Map<Integer, Integer> sizeMap = new HashMap<Integer, Integer>();
            int m = sc.nextInt();
            for (int j = 0; j < m; j++) {
                int a = sc.nextInt();
                int b = sc.nextInt();
                //分别找爹 看看谁的爹大
                int pa= find(parent,a);
                int pb= find(parent,b);
                //如果你爹不等于我爹
                if (pa!=pb){
                    //那么你pb要认我为爹
                    parent.put(pb, pa);
                    //你pb家族的孩子都归我们家族了
                    int pbSize = sizeMap.getOrDefault(pb, 1);
                    int paSize = sizeMap.getOrDefault(pa, 1);
                    sizeMap.put(pa,paSize+pbSize);
                    //pb家族从此除根
                    sizeMap.remove(pb);
                }
            }
            //找哪个家族最庞大 孩子最多 基本就是一map遍历过程
            Iterator<Map.Entry<Integer, Integer>> it = sizeMap.entrySet().iterator();
            int res=1;
            while (it.hasNext()){
                res=Math.max(res,it.next().getValue());
            }
            System.out.println(res);

        }
    }

    //找爹的函数 这里必须扁平化 否则时间过不了
    //解释一下扁平化 就是说1是2爹 2是3爹
    //这样3要找爹的话 肯定3->2  2->1 分两步
    //如果链子很长就不行了 所以现在要乱辈 大家都认一个最大是爹 剩下都是孩子
    //可以想象优化后就是一个N叉树 就两层的 根节点是爹 剩下一排孩子
    private static int find(Map<Integer, Integer> parent, int i) {
        //保存沿途想认最大的爹为爹的孩子节点
        Stack<Integer> s=new Stack<>();
        //循环 只要我还能找到爹 就继续往下找
        while (parent.containsKey(i)){
            s.push(i);
            i=parent.get(i);
        }
        //扁平化
        while (!s.isEmpty()){
            parent.put(s.pop(),i);
        }
        //返回家族最大的爹
        return i;
    }
}
给一个Java我认为我写的挺好的题解 哈哈哈哈哈
发表于 2022-06-21 10:16:23 回复(0)

简单并查集模型

#include <iostream>

const int M = 2000010,N = 100010;

using namespace std;
int t;
int p[N];
int sum[N];

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

int main()
{
    scanf("%d",&t);

    while(t--)
    {
        int n;
        scanf("%d",&n);

        for(int i = 1;i <= N;i++)
        {
            p[i] = i;
            sum[i] = 1;
        }

        int res = 0;
        while(n--)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            int px = find(x),py = find(y);
            if(px != py)
            {
                 p[px] = py;
                sum[py] += sum[px];
            }


            res = max(res,sum[py]);
        }
        printf("%d\n",res);
    }

    return 0;
}
发表于 2022-05-28 22:21:15 回复(0)
#并查集
def init():
    global size, rank, fa
    MAX_VALUE = int(1e5 + 1)
    size = [1] * MAX_VALUE 
    rank = [1] * MAX_VALUE 
    fa = list(range(MAX_VALUE))

def merge(i, j):
    global rank, fa
    x, y = find(i), find(j)
    if rank[i] <= rank[j]:
        fa[x] = y # 如果是同一个祖先节点呢?
        if x != y:
            size[y] += size[x]
    else:
        fa[y] = x
        if x != y:
            size[x] += size[y]
    if (rank[x] == rank[y] and x!=y):
        rank[y] += 1
        

def find(x):
    if x == fa[x]:
        return x
    else:
        fa[x] = find(fa[x])
        return fa[x]

def main():
    init()
    n = int(input())
    for _ in range(n):
        x, y = map(int, input().split(' '))
        merge(x, y)
    print(max(size))
    
    
if __name__ == "__main__":
    t = int(input())
    for _ in range(t):
        main()

发表于 2022-05-14 00:29:56 回复(0)

用了并查集模板就是舒服

import java.util.*;

public class Main{
    static int N = 100010; // 习惯了超出10个
    static int[] p = new int[N + 1]; // 每个用户的父节点
    static int[] size = new int[N + 1]; // 只保证根节点的数量正确有效即可

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int T = sc.nextInt();
        for (int k = 0; k < T; k++) {
            // 每次都初始化所有用户(因为题目给了 T 组测试数据)
            for (int i = 1; i <= N; i++) {
                p[i] = i;
                size[i] = 1;
            }
            int n = sc.nextInt();
            // n对关系
            for (int i = 0; i < n; i++) {
                int x = sc.nextInt();
                int y = sc.nextInt();
                if(find(x) == find(y)) continue; // 不能重复挂
                // x挂到y上 之前,先统计x、y两个集合人数,再把x挂到y
                size[find(y)] += size[find(x)]; //先统计两个集合点数
                p[find(x)] = find(y); // 把x挂到y的根节点上
            }

            // 统计那个最大朋友圈的用户数
            int res = 0;
            for (int i : size) {
                res = Math.max(res, i);
            }
            System.out.println(res);
        }
    }

    // 找出x的根节点(带路径压缩)
    public static int find(int x) {
        if (p[x] != x) p[x] = find(p[x]);
        return p[x];
    }
}
发表于 2022-04-26 16:09:01 回复(0)
python并查集解法,最后一个测试点提交时,有时能通过,有时超时。
n=100001

T=int(input())

#寻找根节点
def getFather(x):
    a=x
    while father[x]!=x:
        x=father[x]

    #路径压缩
    while father[a]!=a:
        z=a
        a=father[a]
        father[z]=x
    return x

for _ in range(T):
    #初始化
    father = [i for i in range(n)]
    isroot=[0]*(n)

    m=int(input())
    for _ in range(m):
         i,j=map(int,input().strip().split())
         if getFather(i)!=getFather(j):
            i=getFather(i)
            j=getFather(j)
            father[j]=i

    res=1
    for i in range(1,n):
        isroot[getFather(i)]+=1
        res=max(res,isroot[getFather(i)])
    print(res)


发表于 2022-04-24 15:24:26 回复(0)
#include<bits/stdc++.h>
using namespace std;

unordered_map<int, int>fa;
unordered_map<int, int>cnt;

int find(int x){
    if(fa.find(x)==fa.end()){
        fa[x]=x;
        cnt[x]=0;
    }
    if(x==fa[x]){
        return x;
    }
    return fa[x]=find(fa[x]);
}
void Union(int x,int y){
    int fx=find(x);
    int fy=find(y);
    fa[fx]=fy;
}
int main(){
    int T;cin>>T;
    while(T-- >0){
        int n;cin>>n;
        while(n-- >0){
            int x,y;
            cin>>x>>y;
            Union(x,y);
        }
        int ans=0;
        for(unordered_map<int, int>::iterator it=fa.begin();it!=fa.end();it++){
            int fi=find(it->second);
            cnt[fi]++;
            ans=max(ans,cnt[fi]);
        }
        cout<<ans<<endl;
        fa.clear();
        cnt.clear();
    }
}

发表于 2022-04-14 10:16:22 回复(0)
using namespace std;
#include<iostream>
#include<algorithm>
#include<numeric>
#include<vector>
//#include<bits/stdc++.h>

vector<int>id(100001, 0);
vector<int>counts(100001, 1);
int maxrs = 0;
int find(int x) {     while (x!=id[x])     {         id[x] = id[id[x]];         x = id[x];     }     return x;
}

void unionxy(int x, int y) {     x = find(x);     y = find(y);     if (x != y) {         if (counts[x] > counts[y]) {             counts[x] += counts[y];             counts[y] = 0;             id[y] = id[x];             if (maxrs < counts[x])                 maxrs = counts[x];         }         else {             counts[y] += counts[x];             counts[x] = 0;             id[x] = id[y];             if (maxrs < counts[y])                 maxrs = counts[y];         }     }      }

int main() {     int T;     cin >> T;          while (T--)     {             int n;         cin >> n;         iota(id.begin(), id.end(), 0);         fill(counts.begin(), counts.end(), 1);         maxrs = 0;         for (int i = 0; i < n; i++) {             int x, y;             cin >> x >> y;             unionxy(x, y);         }         cout << maxrs << endl;     }     return 0;
}

编辑于 2022-04-03 17:04:31 回复(0)
DFS深度优先搜索,将一对一对节点视为一棵树,按题意就是要遍历每一颗树的最大节点,为了减少时间复杂度,引入一个visit[i],表示这个节点i已经访问过了,不必再访问。
#include<iostream>
#include<vector>
#include<unordered_map>

using namespace std;
int deep(int key, unordered_map<int, vector<int>> &mp, unordered_map<int, int> &visit){
    vector<int> tmp = mp[key];//访问当前节点是否有其他子节点
    visit[key] = 1;//并且标志这个节点已经访问过了
    int d = 1;//然后 深度 加1
    for(auto t:tmp){
        if(!visit[t])//如果没有访问
            d += deep(t,mp,visit);//那么当前节点就加上 子节点的深度
    }
    return d;//返回当前节点的深度
}
void func(unordered_map<int, vector<int>> &mp){    
    int ans = 0;
    unordered_map<int, int> visit;
    for(auto [key, vval]:mp){
        if(!visit[key]){//如果这个节点没有访问过,那么这个节点连接的树就是一棵独立的树
            ans = max(ans, deep(key, mp, visit));//求最大深度
        }
    }
    cout<<ans<<endl;
}
int main(){
    std::ios::sync_with_stdio(0);
    cin.tie(0);//加快输入
    
    int T;
    cin>>T;
    while(T--){
        int n;
        cin>>n;
        int x,y;
        unordered_map<int, vector<int>> mp;
        for(int i = 0; i < n; i++){
            cin>>x>>y;
            mp[x].emplace_back(y);//由单向图建立双向图
            mp[y].emplace_back(x);
        }
        func(mp);
    }
    
    return 0;
}


发表于 2022-03-28 21:01:59 回复(0)