并查集
并查集
原理:
对于单独的点来说,进行染色处理,将拥有的最老祖先视为颜色,任意两点进行连接时,查找最老的祖先,如果相同就代表联通,不同就使一方最老祖先变为另一个最老祖先的祖先。
代码实现解释:
- find函数找最终的祖先
int find (int x)
{
while(x!=fa[x])
x=fa[x]=fa[fa[x]];
return x;
}
- 将不同祖先的两点联合
for(int i=1;i<=m;i++)
{
int x=find(a[i].x);
int y=find(a[i].y);
join(x,y);
}
void join(int x,int y)
{
if(x!=y)
{
fa[x]=y;
nofa[y]+=nofa[x];//根据题目添加,板子中没有
sum++;
}
}
代码
#include<iostream>
#include<algorithm>
using namespace std;
int fa[200005];
int nofa[200005];int sum=0;
struct node{
int x,y;
}a[200005];
int find (int x)
{
while(x!=fa[x])
x=fa[x]=fa[fa[x]];
return x;
}
void join(int x,int y)
{
if(x!=y)
{
fa[x]=y;
nofa[y]+=nofa[x];//根据题目添加,板子中没有
sum++;
}
}
int main()
{
int n,m;
cin>>n>>m;
for(int i=1;i<=m;i++)
{
cin>>a[i].x>>a[i].y;
}
for(int i=1;i<=n;i++)
{
fa[i]=i;
nofa[i]=1;
}
for(int i=1;i<=m;i++)
{
int x=find(a[i].x);
int y=find(a[i].y);
join(x,y);
}
int ma=0;
for(int i=1;i<=n;i++)
{
ma=max(ma,nofa[i]);
}
cout<<n-sum<<" "<<ma;
}
find优化
由于连祖先时可能会导致关系树越来越高,比如1->2->3->4->5->6,这时查找1的最老祖先就很麻烦,find优化后可以使得这一次查找链上的点全直连最老祖先
int find (int x)
{
if(fa[x]==x) return x;
return fa[x] = find(fa[x]);
}
加权优化
- 两个树连接时,如果随便挑一个作为另一个祖先,可能导致树的加长,列如:1->2->3->4->5->6和7->8(7为祖先)最优当然是以1为祖先连接,因为连接会使一个树的长度加1,选较短的树加一
- 添加一个rank数组标记树的层数即可
for(int i=1;i<=m;i++)
{
int x=find(a[i].x);
int y=find(a[i].y);
join(x,y);
}
void join(int x,int y)
{
if(x!=y)
{
if(rank[x]>rank[y])
{
fa[y]=x;
nofa[x]+=nofa[y];//根据题目添加,板子中没有
}
else
{
if(rank[x]==rank[y])
{
rank[y]++
}
fa[x]=y;
nofa[y]+=nofa[x];//根据题目添加,板子中没有
}
sum++;
}
}

浙公网安备 33010602011771号