并查集
1.初始化
for(int i =1;i<=n;i++)
fa[i]=i;
对于1到n个元素,用一个数组fa[]来储存每一个元素的父节点。 一开始,我们先将父节点设置为自己
2.查询
找到i的祖先并直接返回,未进行路径压缩
int find(int x)
{
return fa[x] == x ? x: find(fa[x]);
}
路径压缩版//节省时间
int find(int x)
{
return fa[x] == x ? x : fa[x] = find(fa[x]);
}
3.合并
void merge(int x,int y)
{
int fx = find(x);//找到x的祖先
int fy = find(y); //找到y的祖先
if(fx == fy) return ;//如果是同一个祖先,直接跳过
fa[fx] = fy;//x的祖先指向y的祖先
}
4.查询
bool query(int x,int y)
{
int fx = find[x] ,fy = find(y);
if(fx == fy) return true;//如果他们的祖先是同一个,说明他们是一个家族的
else return false;
}
例题:P1551亲戚 题解:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 5e3+5;
ll n,m,p;
ll m1,m2;
ll p1,p2;
ll fa[N];
ll find(ll x)
{
return fa[x] == x ? x : fa[x] = find(fa[x]);
}
void merge(ll x,ll y)
{
ll fx = find(x), fy = find(y);
if(fx == fy) return ;
fa[fx]=fy;
}
ll query(ll x,ll y)
{
ll fx =find(x),fy = find(y);
if(fx == fy) return 1;
return 0;
}
int main()
{
cin>>n>>m>>p;
for(int i=1;i<=n;i++)
fa[i]=i;
for(int i=1;i<=m;i++)
{
cin>>m1>>m2;
merge(m1,m2);
}
for(int i=1;i<=p;i++)
{
cin>>p1>>p2;
if(query(p1,p2))
cout<<"Yes"<<"\n";
else
cout<<"No"<<"\n";
}
return 0;
}
例题:字符串并查集P2256——中校运会之百米跑
map大法!!! 题解:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 2e4+5;
ll n,m,k;
map<string,string> fa;
string find(string s)
{
return fa[s] == s? s:fa[s] = find(fa[s]) ;
}
void merge(string s1,string s2)
{
string fx = find(s1),fy = find(s2);
if(fx == fy) return ;
fa[fx] = fy;
}
bool query(string s1,string s2)
{
string fx = find(s1),fy = find(s2);
if(fx == fy) return true;
else return false;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
string s;
cin>>s;
fa[s]=s;
}
while(m--)
{
string s1;
string s2;
cin>>s1>>s2;
merge(s1,s2);
}
cin>>k;
while(k--)
{
string s1;
string s2;
cin>>s1>>s2;
if(query(s1,s2)) cout<<"Yes."<<"\n";
else cout<<"No."<<"\n";
}
return 0;
}
例题:P1111修复公路
题解:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 1e5+5;
ll n,m;
ll x[N],y[N],t[N];
ll fa[N];
struct node
{
ll x;
ll y;
ll t;
}cv[N];
ll cmd(node sx, node sy)
{
return sx.t<sy.t;
}
ll find(ll x)
{
return fa[x] == x ? x : fa[x] = find(fa[x]);
}
void merge(ll x,ll y)
{
ll fx = find(x) , fy = find(y);
if(fx == fy) return ;
fa[fx] = fy;
}
bool check()
{
ll sum=0;
for(int i=1;i<=n;i++)
{
if(fa[i]==i) sum++;// 找最大的老大,找到后帮派加一
if(sum==2) return 0;//如果出现第二个帮派,就说明路并没有连同在一块,所以直接返回
}
return 1;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
fa[i]=i;
for(int i=1;i<=m;i++)
{
cin>>cv[i].x>>cv[i].y>>cv[i].t;
}
sort(cv+1,cv+1+m,cmd);
for(int i=1;i<=m;i++)
{
merge(cv[i].x,cv[i].y);
if(check())
{
cout<<cv[i].t;
return 0;
}
}
cout<<-1<<"\n";
}
例题:P8654 [蓝桥杯 2017 国 C] 合根植物(水题)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 1e6+5;
ll m,n,k;
ll fa[N];
ll find(ll x)
{
return fa[x] == x ? x : fa[x] = find(fa[x]);
}
void merge(ll x,ll y)
{
ll fx = find(x), fy = find(y);
if(fx == fy) return ;
fa[fx] = fy;
}
ll res;
int main()
{
cin>>m>>n>>k;
ll ans= m*n;
for(int i=1;i<=ans;i++)
{
fa[i]=i;
}
while(k--)
{
ll a,b;
cin>>a>>b;
merge(a,b);
}
for(int i=1;i<=ans;i++)
{
if(fa[i]==i)
{
res++;
}
}
cout<<res;
return 0;
}