数据结构--并查集

一、概述

1、定义:并查集是一种树型的数据结构

2、应用:用于处理不相交的集合的合并和查询。

二、操作及实现

1、查询:找到自己的老大

cpp 复制代码
int find(int x)
{
    while(f[x]!=x)//如果自己的老大不是自己说明老大另有其人
    {
        x=f[x];//接着往下找老大
    }
    return x;//找到了老大
}

2、合并:合并成一个团伙

cpp 复制代码
void join(int x,int y)
{
    int fx=find[x],fy=find[y];//找到两个人各自的老大
    if(fx!=fy)//如果两个人的老大不一样说明不是一个团伙
    {
        f[fx]=fy;//要合并成一个团伙,只能有一个老大,所以说其中一个老大要认另一个老大做新老大。
    }
}

3、路径压缩:(优化find函数)

如果树的深度过深,查询起来会相当耗时,所以说要减短树的深度。

可以将查询点x到根节点(也就是老大)的途径的点的父节点都设成为根节点,会大大降低查询的难度。

缺点是:只有当找到老大时,才能进行路径压缩,所以每个团体第一次的查询是没有什么优化的,之后才会生效。

cpp 复制代码
int find(int x)//路径压缩 
{
	if(f[x]==x)return x;//如果自己的老大是自己输出
	return f[x]=find(f[x]);//如果不是,继续找老大,并且把自己的父节点设为老大
}

三、模板和例题

1、模板

洛谷P3367

https://www.luogu.com.cn/problem/P3367#submithttps://www.luogu.com.cn/problem/P3367#submit

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int f[N],a,b,c;
int find(int k)
{
	//路径压缩 
	if(f[k]==k)return k;
	return f[k]=find(f[k]);
}
int main()
{
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		f[i]=i;//初始化老大为自己 
	}
	for(int i=1;i<=m;i++)
	{
		cin>>a>>b>>c;
		if(a==1)
		{
			f[find(b)]=find(c);//合并  c所在组赢了b所在组 
		}
		else
		{
			if(find(b)==find(c))//检查老大是否相同 
			{
				cout<<"Y"<<endl;
			}
			else
			{
				cout<<"N"<<endl;
			}
		}
	}
	return 0;
} 

2、acwing 837、连通块中点的数量

https://www.acwing.com/problem/content/839/

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n,m,f[N],cnt[N];
int find(int x)//不能用路径压缩因为那样的话就没办法统计连通快的数量了
{
    if (f[x] != x) f[x] = find(f[x]);
    return f[x];
}
void join(int x,int y)
{
    int fx=find(x),fy=find(y);
    if(fx!=fy)
    {
        f[fx]=fy;
    }
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        f[i]=i;
        cnt[i]=1;
    }
    while(m--)
    {
        string flag;
        cin>>flag;
        int a,b;
        if(flag=="C")
        {
            cin>>a>>b;
            if(find(a)==find(b))continue;
            cnt[find(b)]+=cnt[find(a)];//先加连通块数量,否则先操作集合的话会导致重叠。而且要给新老大加,不能加错
            join(a,b);
        }
        else if(flag=="Q1")
        {
            cin>>a>>b;
            if(find(a)==find(b))
            {
                cout<<"Yes"<<endl;
            }
            else
            {
                cout<<"No"<<endl;
            }
        }
        else
        {
            cin>>a;
            cout<<cnt[find(a)]<<endl;
        }
    }
    return 0;
}

3、acwing 240食物链

cpp 复制代码
//把食物环拆成食物链,用某节点到根节点的距离%3的余数来表示各节点之间的关系。
/*
余1:吃根节点
余2:被根节点吃
余0:同类
*/
#include<bits/stdc++.h>
using namespace std;
const int N=5e4+10;
int f[N],d[N];
int n,m;
int find(int x)
{
    if(f[x]!=x)//自己不是根节点
    {
        int t=find(f[x]);//先压缩路径使除x外的所有上级都指向根节点并记录根节点是谁
        d[x]+=d[f[x]];//到根节点的距离更新为x到其父节点的距离+父节点到根节点的距离
        f[x]=t;//再让x指向根节点
    }
    return f[x];
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        f[i]=i;
    }
    int res=0;
    while(m--)
    {
        int t,x,y;
        cin>>t>>x>>y;
        if(x>n||y>n)
        {
            res++;
            continue;
        }
        int fx=find(x),fy=find(y);
        if(t==1)//同类
        {
            //在同一集合中
            if(fx==fy&&(d[x]-d[y])%3)res++;//两者%3不相等,说明不是同一类,谎话++
            else if(fx!=fy)//不在同一集合中,先到者为真
            {
                f[fx]=fy;//合并集合,让其中一个老大认另一个人做老大
                d[fx]=d[y]-d[x];//因为同类,所以(d[x]+d[fx]-d[y])%3==0
            }
        }
        //同上
        else
        {
            if(fx==fy&&(d[x]-d[y]-1)%3)res++;
            else if(fx!=fy)
            {
                f[fx]=fy;
                d[fx]=d[y]+1-d[x];
            }
        }
    }
    cout<<res<<endl;
    return 0;
}
相关推荐
不穿格子的程序员3 小时前
从零开始写算法——链表篇2:从“回文”到“环形”——链表双指针技巧的深度解析
数据结构·算法·链表·回文链表·环形链表
诺....3 小时前
C语言不确定循环会影响输入输出缓冲区的刷新
c语言·数据结构·算法
长安er5 小时前
LeetCode876/141/142/143 快慢指针应用:链表中间 / 环形 / 重排问题
数据结构·算法·leetcode·链表·双指针·环形链表
workflower5 小时前
PostgreSQL 数据库的典型操作
数据结构·数据库·oracle·数据库开发·时序数据库
仰泳的熊猫5 小时前
1140 Look-and-say Sequence
数据结构·c++·算法·pat考试
EXtreme356 小时前
栈与队列的“跨界”对话:如何用双队列完美模拟栈的LIFO特性?
c语言·数据结构·leetcode·双队列模拟栈·算法思维
松涛和鸣6 小时前
29、Linux进程核心概念与编程实战:fork/getpid全解析
linux·运维·服务器·网络·数据结构·哈希算法
hweiyu006 小时前
数据结构:有向图
数据结构
呱呱巨基6 小时前
C++ 红黑树
数据结构·c++·笔记·学习