并查集基础:
并查集核心代码:
查找:
int find(int x) {//查找
if(x!=f[x]) return f[x]=find(f[x]);
return f[x];
合并:
void Union (int x,int y) {//合并
int tx=find(x);
int ty=find(y);
if(tx!=ty) f[tx]=f[ty];
}
基础题目:
HDU1213(并集查)
Problem Descrption
Today is Ignatius’ birthday. He invites a lot of friends. Now it’s dinner time. Ignatius wants to know how many tables he needs at least. You have to notice that not all the friends know each other, and all the friends do not want to stay with strangers.
One important rule for this problem is that if I tell you A knows B, and B knows C, that means A, B, C know each other, so they can stay in one table.
For example: If I tell you A knows B, B knows C, and D knows E, so A, B, C can stay in one table, and D, E have to stay in the other one. So Ignatius needs 2 tables at least.
Input
The input starts with an integer T(1<=T<=25) which indicate the number of test cases. Then T test cases follow. Each test case starts with two integers N and M(1<=N,M<=1000). N indicates the number of friends, the friends are marked from 1 to N. Then M lines follow. Each line consists of two integers A and B(A!=B), that means friend A and friend B know each other. There will be a blank line between two cases.
Output
For each test case, just output how many tables Ignatius needs at least. Do NOT print any blanks.
Sample Input
2
5 3
1 2
2 3
4 5
5 1
2 5
Sample Output
2
4
//题目大意是,有n个人一起吃饭,认识的人坐在一起,比如1与2认识,2与3认识,那么1,2,3坐在一起吃饭,n个人,m组认识,问需要几张桌子吃饭
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 0x7fffffff
int f[500005];
int find(int x) {//查找
if(x!=f[x]) return f[x]=find(f[x]);
return f[x];
}
void Union(int x,int y) {//合并
int tx=find(x);
int ty=find(y);
if(tx!=ty) f[tx]=f[ty];
}
int main() {
int t;
cin>>t;
while(t--) {
int n,m,ans=0;
cin>>n>>m;
for(int i=0; i<=n; i++) f[i]=i;
while(m--) {
int x,y;
cin>>x>>y;
Union(x,y);
}
for(int i=1;i<=n;i++){
if(f[i]==i)
ans++;
}
cout<<ans<<endl;
}
return 0;
}
种类并查集
https://www.lanqiao.cn/problems/1136/learning/
题目描述
小明是蓝桥王国的侦探。这天,他接收到一个任务,任务的名字叫分辨是非,具体如下:蓝桥皇宫的国宝被人偷了,犯罪嫌疑人锁定在 N 个大臣之中,他们的编号分别为 1\∼N。在案发时这 NN 个大臣要么在大厅11,要么在大厅22,但具体在哪个大厅他们也不记得了。审讯完他们之后,小明把他们的提供的信息按顺序记了下来,一共 M 条,形式如下:x y,表示大臣 xx 提供的信息,信息内容为:案发时他和大臣 yy 不在一个大厅。小明喜欢按顺序读信息,他会根据信息内容尽可能对案发时大臣的位置进行编排。他推理得出第一个与先前信息产生矛盾的信息提出者就是偷窃者,但推理的过程已经耗费了他全部的脑力,他筋疲力尽的睡了过去。作为他的侦探助手,请你帮助他找出偷窃者!
输入描述
第 11 行包含两个正整数 N,MN,M,分别表示大臣的数量和口供的数量。之后的第 2 ∼M+1 行每行输入两个整数 x , y,表示口供的信息。
1< N,M 10^5 ,1≤x,y≤N。
输出描述
输出仅一行,包含一个正整数,表示偷窃者的编号。
输入输出样例
示例 1
输入
4 5
1 2
1 3
2 3
3 4
1 4
输出
2
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 0x7fffffff
int f[5000050],ans;
int find(int x) {//查找
if(x!=f[x]) return f[x]=find(f[x]);
return f[x];
}
void Union (int x,int y) {//合并
int tx=find(x);
int ty=find(y);
if(tx!=ty) f[tx]=f[ty];
}
int main() {
int n,m;
cin>>n>>m;
for(int i=0; i<=2*n; i++) f[i]=i;
while(m--) {
int x,y;
cin>>x>>y;
if(ans) break;
else {
if(find(x)==find(y)||find(x+n)==find(y+n)) ans=x;//不可能即使朋友又是敌人
Union(x,y+n);//朋友的朋友是朋友 ,敌人的朋友也是朋友
Union(y,x+n);
}
}
cout<<ans<<endl;
return 0;
}