数据结构—并查集

版权声明:QAQ https://blog.csdn.net/priesty_/article/details/82939757

·并查集:


     并查集是一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问


1.常规做法:

easy girl,easy come on QAQ

int find(int x)
{
	if(fa[x]==x) return x;
	return find(fa[x]);
}

2.路径压缩:

                      对于不相交集合的操作,一般采用两种启发式优化的方法: 

                    1. 按秩合并:使包含较少结点的树根指向包含较多结点的树根。 

                    2. 路径压缩:使路径查找上的每个点都直接指向根结点

 

平时用路径压缩就ok,能解决很多东西√

按秩合并↓↓↓

int find(int x)
{
	if(fa[x]==x) return x;
	return find(fa[x]);
}

void Union(int x, int y)
{
	x=find(x),y=find(y);
	if(x!=y)
	{
		if(rank[x]>rank[y]) fa[y]=x;
		else
		{
			fa[x]=y;
			if(rank[x]==rank[y])
				rank[y]++;
		}
	}
}

路径压缩↓↓↓

int find(int x)
{
	if(x!=fa[x]) fa[x]=find(fa[x]);
	return fa[x];
}

int find__(int x)
{
	int fx=x;
	while(fa[x]!=fx) fx=fa[x];
	while(fx!=x)
	{
		int rt=fa[x];
		fa[x]=fx;
		x=rt;
	}
	return x;
}

·带权并查集:

是指在并查集中加入了一个dist[ ]数组

数组可以记录很多种东西,不一定是类似距离这种东西,也可以是相对于根节点的状态;

emmmm我写的比较简陋↓↓↓

int find_(int x)
{
	if(fa[x]==x) return x;
	int root=find(fa[x]);
	dist[x]+=dist[fa[x]];
	return fa[x]=root;
}

至于具体的再根据题目调整啦

·类型题

洛谷p2024食物链[模板题]

又把题翻出来重写了一遍……以前写的太丑了……

虽然现在也没好到哪里去,依旧写得很累赘QAQ,代码风格极骚

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cstdlib>
#include<vector>
#include<queue>
#include<stack>
#include<algorithm>
#include<deque>
#include<cmath>
#include<cctype>
#define LL long long
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1

using namespace std;

const int maxn=100000+5;

int n,k;
int ans=0;
int fa[maxn];
int dist[maxn];

int read()
{
	char c=getchar();int x=0,f=1;
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
	return x*f;
}

void init(int n)
{
	for(int i=0;i<=n;i++)
	{
		fa[i]=i;
		dist[i]=0;
	}
}

int find_(int x)
{
	if(fa[x]==x) return x;
	int root=find_(fa[x]);
	dist[x]=(dist[x]+dist[fa[x]])%3;
	return fa[x]=root;
}

void Union(int v,int x,int y)
{
	int fx=find_(x);
	int fy=find_(y);
	if(fx!=fy)
	{
		fa[fx]=fy;
		dist[fx]=(v+dist[y]-dist[x]+3)%3;
	}
}

int main()
{
	n=read(),k=read();
	init(n);
	ans=0;
	for(int i=1;i<=k;i++)
	{
		int a=read(),b=read(),c=read();
		a--;
		if(b>n || c>n)
		{
			ans++;
			continue;
		}
		if(a==1 && b==c)
		{
			ans++;
			continue;
		}
		int fx=find_(b);
		int fy=find_(c);
		if(fx!=fy) Union(a,b,c);
		else
		{
			if((dist[b]-dist[c]+3)%3!=a) ans++;
		}
	}
	cout<<ans<<endl;

	return 0;
}

poj2492 A Bug‘s life  (虫虫总动员?QAQ开玩笑的啦)

题意:
        给出T组数据,每组数据表示有n只虫和m对关系,接下来m行输入(x,y),表示x和y是相爱的异性,若这m对关系中出现了错误,即后给出的关系与之前的关系互相冲突(同性相爱),则输出“Suspicious bugs found!”,否则输出“No suspicious bugs found!”

       关系并查集,带权的第二类;

       用rank[i]来表示i与根节点的关系,rank[]=1表示同性,rank[]=0表示异性;

      以下,供上调了很久WA无数次,最后发现是输出大小写错误的代码QAQ↓↓↓

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cstdlib>
#include<vector>
#include<queue>
#include<stack>
#include<algorithm>
#include<deque>
#include<cmath>
#include<cctype>
#define LL long long
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1

using namespace std;

const int maxn=2000+10;

int n,m;
bool flag=0;
int fa[maxn];
int rank[maxn];

int read()
{
	char c=getchar();int x=0,f=1;
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
	return x*f;
}

void init()
{
	for(int i=0;i<=maxn;i++)
	{
		fa[i]=i;
		rank[i]=1;
	}
	flag=0;
}

int find(int x)
{
	if(fa[x]==x) return x;
	int root=find(fa[x]);
	rank[x]=(rank[x]+rank[fa[x]]+1)&1;
	return fa[x]=root;
}

void Union(int x,int y)
{
	int fx=find(x);
	int fy=find(y);
	if(fx!=fy)
	{
		fa[fx]=fy;
		rank[fx]=(rank[x]+rank[y])&1;
	}
	else
	{
		if(!((rank[x]+rank[y])&1)) flag=1;
	}
}

int main()
{
	int Case=0;
	int t=read();
	while(t--)
	{
		init();
		n=read(),m=read();
		for(int i=1;i<=m;i++)
		{
			int a=read(),b=read();
			Union(a,b);
		}
		printf("Scenario #%d:\n",++Case);
		if(flag)
		{
			printf("Suspicious bugs found!\n");
		}
		else printf("No suspicious bugs found!\n");
		puts("");
	}

	return 0;
}

emmmm就先写到这儿,以后有时间再补上……像可持久化并查集之类的……


 

猜你喜欢

转载自blog.csdn.net/priesty_/article/details/82939757