给定若干个32位int数字集合,每个集合中的数字无重复,譬如:
{1,2,3} {2,5,6} {8}
将其中交集不为空的集合合并,保证合并完成后所有集合之间无交集,输出合并后的集合个数以及最大集合中元素的个数。
输入格式:
1. 第一行为一个数字N,表示集合数。
2. 接下来N行,每行一个非空集合,包含若干个数字,数字之间用空格分开。
假设第i个集合的大小为Si,数据满足N<=100000,ΣSi<=500000
输出格式:
1. 第一行为合并后的集合个数。
2. 第二个为最大集合中元素的个数。
3 1 2 3 2 5 6 8
2 5
N = int(input())
sets = [list(map(int, input().split())) for _ in range(N)]
# parent用来记每个数的父节点
# nums用来记每个根节点的树中有几个节点
parent, nums = {}, {}
for _set in sets:
# 对于每个集合,默认取第一个元素为根节点来构造树
p = _set[0]
# 根节点为p的树默认有0个元素
nums.setdefault(p, 0)
for s in _set:
# 如果当前数没有出现在parent中,说明是个新的数,把它添加进来并以p作为它的父节点
if s not in parent:
parent[s] = p
nums[p] += 1
# 如果当前数已经出现过,它必然有一个父节点,且可以根据父节点向上找到根节点,
# 于是把一路经过的所有节点都指向p,相当于一个层级压缩,让p成为新的根节点
# 同时把原先的根节点中的计数赋给p
else:
while parent[s] != p:
temp = parent[s]
parent[s] = p
s = temp
parent[s] = p
if s != p and s in nums:
nums[p] += nums[s]
del nums[s]
print(len(nums.keys()))
print(max(nums.values())) /*
并查集算法
*/
#include <bits/stdc++.h>
using namespace std;
class DisjointSet
{
private:
std::unordered_map<int, int> parent;
std::unordered_map<int, int> rank; // 秩
public:
void add(int x)
{
if(parent.find(x) == parent.end()) {
parent[x] = x;
rank[x] = 0;
}
}
int find(int x)
{
// 查找根节点,并包含路径压缩,提高运行效率
return x == parent[x] ? x : (parent[x] = find(parent[x]));
}
void to_union(int x1, int x2)
{
int f1 = find(x1);
int f2 = find(x2);
if (f1 == f2) return;
// 按秩合并,find-union操作最坏的运行时间提高至O(log n)
if (rank[f1] > rank[f2])
parent[f2] = f1;
else {
parent[f1] = f2;
if (rank[f1] == rank[f2])
++rank[f2];
}
}
void printRes()
{
int cnt = 0, len_max;
map<int, int> set;
for(auto it = parent.begin(); it != parent.end(); it++) {
find(it->first); // 将所有节点到根节点的距离压缩至1步
if(set.find(it->second) == set.end()) set[it->second] = 0;
set[it->second]++; // 统计合并后每个集合的大小
if(it->first == it->second) cnt++; // 当根节点为本身时,集合数加一
}
for(auto p = set.begin(); p != set.end(); p++)
len_max = max(len_max, p->second);
cout << cnt << endl << len_max << endl;
// for(auto it = parent.begin(); it != parent.end(); it++) {
// cout << it->first << " " << it->second << endl;
// }
}
};
int main(void)
{
DisjointSet ans = DisjointSet();
int n, a, b;
cin >> n;
while(n--) {
scanf("%d", &a);
ans.add(a);
while(getchar() != '\n') {
scanf("%d", &b);
ans.add(b);
ans.to_union(a, b);
}
}
ans.printRes();
return 0;
}
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.HashMap;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String line;
while((line = br.readLine()) != null){
int n = Integer.parseInt(line);
UnionFind uf = new UnionFind();
// 边读取数据边对并查集中的元素进行合并
for(int i = 0; i < n; i++){
String[] str = br.readLine().split(" ");
int[] set = new int[str.length];
for(int j = 0; j < set.length; j++){
set[j] = Integer.parseInt(str[j]);
uf.add(set[j]);
if(j > 0) {
uf.union(set[j], set[j - 1]); // 合并集合
}
}
}
// 获得连通分量数
System.out.println(uf.getCount());
// 获得最大连通分量大小
System.out.println(uf.getMaxSize());
}
}
}
class UnionFind {
int count; // 连通分量数
int maxSize; // 最大集合的规模
private HashMap<Integer, Integer> parent; // 节点->根
private HashMap<Integer, Integer> rank; // 节点->树的大小
public UnionFind(){
parent = new HashMap<Integer, Integer>();
rank = new HashMap<Integer, Integer>();
maxSize = 1;
}
public void add(int num) {
if(!parent.containsKey(num)){
parent.put(num, num);
rank.put(num, 1);
count++;
}
}
private int find(int x){
int root = x;
while(parent.get(root) != root){
root = parent.get(root);
}
// 把沿途节点的根都修改为father
while(x != root){
int temp = parent.get(x);
parent.put(x, root);
x = temp;
}
return root;
}
public void union(int x, int y){
int rootX = find(x);
int rootY = find(y);
if(rootX == rootY){
return;
}
int rankX = rank.get(rootX);
int rankY = rank.get(rootY);
if(rankX < rankY){
parent.put(rootX, rootY); // y的树高就将x合并到y
rank.put(rootY, rankX + rankY);
maxSize = Math.max(maxSize, rank.get(rootY));
}else{
// 高度相等时随便合并,但是树的最大高度会增加
parent.put(rootY, rootX);
rank.put(rootX, rankX + rankY);
maxSize = Math.max(maxSize, rank.get(rootX));
}
count--;
}
public int getCount(){
return count;
}
public int getMaxSize(){
return maxSize;
}
} #include <iostream>
#include <cstring>
#include <algorithm>
#include <unordered_map>
using namespace std;
unordered_map<int, int> p;
unordered_map<int, int> cnt;
int find(int x) {
if(p[x] != x) p[x] = find(p[x]);
return p[x];
}
void merge(int pa, int pb) {
if(cnt[pa] >= cnt[pb]) {
p[pb] = p[pa];
cnt[pa] += cnt[pb];
cnt[pb] = 0;
} else {
p[pa] = p[pb];
cnt[pb] += cnt[pa];
cnt[pa] = 0;
}
}
int main() {
int n;
cin >> n;
for(int i=0; i<n; i++) {
int a, b;
cin >> a;
if(!p.count(a)) {
p[a] = a;
cnt[a] = 1;
}
while(getchar() != '\n') {
cin >> b;
if(!p.count(b)) {
p[b] = find(a);
cnt[find(a)] ++ ;
} else {
int pb = find(b), pa = find(a);
if(pb != pa) {
merge(pb, pa);
}
}
}
}
int res1 = 0, res2 = 0;
for(auto v : cnt) {
if(v.second != 0) {
res1 ++ ;
res2 = max(res2, v.second);
}
}
cout << res1 << endl << res2 << endl;
return 0;
} while True:
try:
n = int(input())
a = []
maxlth = 0
for i in range(n):
data = {int(x) for x in input().split()}
a.append(data)
maxlth = max(maxlth, len(data))
j = len(a)
b = []
while j > 1:
if len(a[-1] & a[j-2]) > 0:
b.append(j-2)
j -= 1
for k in b:
a[-1] |= a[k]
maxlth = max(maxlth, len(a[-1]))
a.pop(k)
print(len(a))
print(maxlth)
except:
break 讨论区也有并查集算法,大家可以学习一下,我也在学习parent = {}
size = {}
def find(x):
if x==parent[x]:
return x
else:
parent[x]=find(parent[x])
return parent[x]
#
'''
def find(a):
cur = a
while(cur!=parent[cur]):
cur = parent[cur]
parent[a]=cur
return cur
'''
#
def union(a,b):
if a not in parent.keys():
parent[a]=a
size[a]=1
if b not in parent.keys():
parent[b]=b
size[b] = 1
if a==b:
return
fa = find(a)
fb = find(b)
if fa==fb:
return
if size[fa]>=size[fb]:
size[fa]=size[fa]+size[fb]
parent[fb]=fa
else:
size[fb]=size[fa]+size[fb]
parent[fa]=fb
m = int(input())
for _ in range(m):
cur = list(map(int,input().split()))
union(cur[0],cur[0])
for i in range(1,len(cur)):
union(cur[0],cur[i])
a = set()
for i in parent.keys():
a.add(find(i))
print(len(a))
print(max(size.values()))
有 java ac 过的吗,我已经优化到我的极致了,还是卡 66.67% 超时,我太难了。
我的一些优化:
import java.util.*;
public class Main {
private static Map<Integer, Integer> parent = new HashMap<>();
private static Map<Integer, Integer> size = new HashMap<>();
private static Map<Integer, Integer> rank = new HashMap<>();
private static int max = 0;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = Integer.valueOf(sc.nextLine());
for(int i = 0; i < n; i ++) {
String[] strs = sc.nextLine().split("\\s+");
int[] arr = new int[strs.length];
for(int j = 0; j < strs.length; j ++) {
Integer num = Integer.valueOf(strs[j]);
arr[j] = num;
parent.putIfAbsent(num, num);
size.putIfAbsent(num, 1);
rank.putIfAbsent(num, 1);
}
unionSet(arr, 0, arr.length - 1);
}
int count = 0;
for(Integer k : parent.keySet()) {
if(k.equals(parent.get(k))) count ++;
}
System.out.println(count);
System.out.println(max);
}
public static int unionSet(int[] arr, int start, int end) {
if(start >= end) return find(arr[start]);
int mid = (start + end) >>> 1;
int leftRoot = unionSet(arr, start, mid);
int rightRoot = unionSet(arr, mid + 1, end);
return union(leftRoot, rightRoot);
}
public static int find(int x) {
if(x != parent.get(x)) {
parent.put(x, find(parent.get(x)));
}
return parent.get(x);
}
public static int union(int p, int q) {
int pRoot = find(p);
int qRoot = find(q);
if(pRoot == qRoot) return pRoot;
if(rank.get(pRoot) < rank.get(qRoot)) {
parent.put(pRoot, qRoot);
size.put(qRoot, size.get(pRoot) + size.get(qRoot));
max = Math.max(max, size.get(qRoot));
return qRoot;
} else {
parent.put(qRoot, pRoot);
size.put(pRoot, size.get(pRoot) + size.get(qRoot));
max = Math.max(max, size.get(pRoot));
if(rank.get(pRoot).equals(rank.get(qRoot))) {
rank.put(pRoot, rank.get(pRoot) + 1);
}
return pRoot;
}
}
}
import java.util.*;
public class Main {
public static void main(String[] args){
Scanner scanner=new Scanner(System.in);
int n=scanner.nextInt();
scanner.nextLine();
Set<Integer>[] set=new HashSet[n];
for(int i=0;i<n;i++){
String s=scanner.nextLine();
set[i]=new HashSet<Integer>();
String[] str=s.split(" ");
for(int j=0;j<str.length;j++)
set[i].add(Integer.parseInt(str[j]));
}
int count=n;//记录集合各数
int max=set[0].size();//记录最大集合里有多少个元素
int sign;//每一次并集最后一个集合的位置。
for(int i=0;i<n-1;i++) {
sign=i;
if(set[i].isEmpty())
continue;
for (int j = i+1; j < n; j++) {
if (set[j].isEmpty())
continue;
if (compare(set[i],set[j])) {
set[i].addAll(set[j]);
set[j].clear();
count--;
sign=j;
if (max < set[i].size()) {
max = set[i].size();
}
}
}
if(sign!=i) {
set[sign].addAll(set[i]);//换到后面可以把之前没法并集,现在可以并集的集合,并集。
}
}
System.out.println(count);
System.out.println(max);
}
public static boolean compare(Set<Integer> set1,Set<Integer> set2){
Iterator<Integer> iterator=set2.iterator();
while(iterator.hasNext()){
if(set1.contains(iterator.next()))
return true;
}
return false;
}
}
有没有大佬可以抢救下,超时了。import java.util.Scanner;
import java.util.HashMap;
import java.util.List;
import java.util.ArrayList;
class UF {
int maxCount; // 最大集合的元素个数
int count; // 集合个数
HashMap<Integer, Integer> parent; // value 是 key 所在集合的根节点
HashMap<Integer, Integer> counter; // value 是 key 所在集合的元素个数
public UF() {
count = 0;
maxCount = 0;
parent = new HashMap<Integer, Integer>();
counter = new HashMap<Integer, Integer>();
}
public int count() {
return count;
}
public int maxCount() {
return maxCount;
}
public int find(int p) {
int root = p;
while (root != parent.get(root)) {
root = parent.get(root);
}
// 路径压缩
while (p != root) {
int temp = parent.get(p);
parent.put(p, root);
p = temp;
}
return root;
}
public void union(int p, int q) {
int i = find(p);
int j = find(q);
if (i == j) return;
if (counter.get(i) < counter.get(j)) {
parent.put(i, j);
counter.put(j, counter.get(j) + counter.get(i));
if (maxCount < counter.get(j)) maxCount = counter.get(j);
} else {
parent.put(j, i);
counter.put(i, counter.get(i) + counter.get(j));
if (maxCount < counter.get(i)) maxCount = counter.get(i);
}
count--;
}
}
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = Integer.valueOf(sc.nextLine());
List<int[]> list = new ArrayList<>();
UF uf = new UF();
while (sc.hasNextLine()) {
String[] strs = sc.nextLine().trim().split(" ");
int[] nums = new int[strs.length];
for (int i = 0; i < nums.length; i++) {
nums[i] = Integer.valueOf(strs[i]);
if (!uf.parent.containsKey(nums[i])) {
uf.parent.put(nums[i], nums[i]);
uf.counter.put(nums[i], 1);
uf.count++;
}
}
int p = nums[0];
for (int i = 1; i < nums.length; i++) {
list.add(new int[] {p, nums[i]});
}
}
for (int[] pair : list) {
uf.union(pair[0], pair[1]);
}
System.out.println(uf.count);
System.out.println(uf.maxCount);
}
}