【ACM算法】-- 图论篇 - 并查集

第一题:
在这里插入图片描述
【ACM算法】-- 图论篇 - 并查集_第1张图片
【ACM算法】-- 图论篇 - 并查集_第2张图片
此篇是图论的开篇:并查集,简要的说一下并查集的相关知识。

  1. 定义,并查集的定义是由集合衍生而来,用来表示某些元素是否属于同一集合,如果存在于同一集合,则其拥有共同的祖先。
  2. 存储结构,存储结构是用双亲表示法来存储,以一维数组的形式存在。
  3. 合并,并查集在判断集合操作时,只涉及到合并操作,而合并操作,是将其中一棵树的根节点的双亲节点变为另一棵树的根节点。这样两棵树就合并成一棵树了。
  4. 优化操作,如果只是如上这种合并方法,这是会形成单支树这种特殊情况,而我们用并查集,就是来找根节点的,所以只要我们的目标是寻找根节点,那么我们就可以把并查集进行优化,即路径压缩。防止单支树寻找根节点时间效率过低。

思路: 这道题的想法是找出图的连通分支数,最后有几个连通分支,在这些连通分支上在加上一条路,这时,这个工程就畅通了,所以我们应用并查集,是为了寻找有几个集合,即连通分支数。

注意: 此题思想并不在如何存储图,而是只要之间连接有路,就可以按照并查集来合并。并查集是集合,只与节点有关,与路边等无关。

代码如下:

#include
#define N 1000
int Tree[N];
int findRoot(int x){
	if(Tree[x]==-1)return x;
	else{
		int tmp=findRoot(Tree[x]);
		Tree[x]=tmp;
		return tmp;
	}
}//并查集模板函数,背住。
int main(){
	int n,m;
	freopen("in.txt","r",stdin);
	while (scanf("%d",&n)!=EOF&&n!=0){
		scanf("%d",&m);
		for(int i=1;i<=n;i++)Tree[i]=-1;
		while(m--){
			int a,b;
			scanf("%d%d",&a,&b);
			a=findRoot(a);
			b=findRoot(b);
			if(a!=b){
				Tree[a]=b;
			}//根据题目构建并查集
		}
		int ans=0;
		for(int i=1;i<=n;i++){
			if(Tree[i]==-1)ans++;
		}
		printf("%d\n",ans-1);
	}
	return 0;
}

第二题:

【ACM算法】-- 图论篇 - 并查集_第3张图片
【ACM算法】-- 图论篇 - 并查集_第4张图片
【ACM算法】-- 图论篇 - 并查集_第5张图片
在这里插入图片描述

思路: 此题可以说是并查集的经典应用

代码如下:

#include
#define N 10000001
int Tree[N];
int findRoot(int x){
	if(Tree[x]==-1) return x;
	else{
		int tmp=findRoot(Tree[x]);
		Tree[x]=tmp;
		return tmp;
	}
}
int sum[N];
int main(){
	int n;
	freopen("in.txt","r",stdin);
	while(scanf("%d",&n)!=EOF){
		for(int i=1;i<=N;i++){
			Tree[i]=-1;
			sum[i]=1;
		}//初始状态,共n个节点,各自为伍 
		while(n--){
			int a,b;
			scanf("%d%d",&a,&b);
			a=findRoot(a);
			b=findRoot(b);
			if(a!=b){
				Tree[a]=b;
				sum[b]=sum[a]+sum[b];	
			}
		} 
		int ans=1;
		for(int i=1;i<=N;i++){
			if(Tree[i]==-1&&sum[i]>ans) ans=sum[i];
		}
		printf("%d\n",ans);
	}
	
	return 0;
}

你可能感兴趣的:(【ACM算法】-- 图论篇 - 并查集)