并查集刷题整理

并查集刷题整理

并查集是一种数据结构,然而用于维护其的数组及函数又极少,用途极为广泛,被广泛地应用于极多的综合题目,

比较经典的应用就是最小生成树\(kruskal\)算法

T1:Watering Hole G

题意

\(n\)个牧场,需要挖井,在第\(i\)号农场挖需要\(W_i\)元,在\(i\)与\(j\)号之间通水需要\(P_{i,j}=P_{j,i}\)元,问最小花费.

思路:

显然这并不是最短路问题,是最小生成树问题,目的就是将所有农场通过花费最小的路径进行串通

对于"挖井"这个放在最小生成树中稍显生疏的操作,实际上通过建新点的操作,可以将挖井的初始花费转变成"地下水到井"的距离,以此将挖井的初始花费转变成边,进行\(kruskal\)

代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
const int N=305;
int n;
struct Ed{
	int from,to,dis;
};
bool operator<(const Ed &a,const Ed &b){
	return a.dis<b.dis;
}
bool operator>(const Ed &a,const Ed &b){
	return a.dis>b.dis;
}
priority_queue<Ed,vector<Ed>,greater<Ed> > q;
int fa[N];
inline int find(int x){
	if(fa[x]==x) return x;
	return fa[x]=find(fa[x]);
}
int main(){
	//freopen("P1550_2.in","r",stdin);
	scanf("%d",&n);
	for(int i=0;i<=n;++i) fa[i]=i;
	for(int i=1;i<=n;++i){
		int dis;
		scanf("%d",&dis);
		q.push((Ed){0,i,dis});
	}
	for(int i=1;i<=n;++i)
		for(int j=1;j<=n;++j){
			int dis;
			scanf("%d",&dis);
			if(i!=j)
				q.push((Ed){i,j,dis});
		}
	int ans=0;
	while(!q.empty()){
		Ed u=q.top();
		q.pop();
		int x=u.from,y=u.to;
		if(find(x)==find(y)) continue;
		ans+=u.dis;
		fa[fa[x]]=fa[y];
	}
	printf("%d\n",ans);
	return 0;
}

p.s.

本题需要注意的是在进行按边权排序的时候,最好用小根堆,不要用结构体数组+\(sort\)函数,因为凿井价值的加入,并不好掌握边的数量,不方便对边进行排序,容易出错

T2:同学

题意:

\(A\)与\(B\)两个公司,\(A\)公司全部是男员工,\(B\)全部是女员工,分别有\(n\),\(m\)个员工,,分别有\(p\),\(q\)条公司内的关系,问最多通过两公司的1号员工能够配成多少情侣

思路:

看上去这是二分图匹配,毕竟是求匹配方案,但是这就奇怪在两公司之间并没有关系,只是单纯通过两公司的1号进行交流,这样一来,将题意转化,就可以明确:

其实就是要求两公司内与1号员工有直接或间接关系的员工的数目的较小值

再次翻译:

在两边各跑一遍并查集看哪个公司中与1号员工属同一集合的员工数较小

代码:

#include<iostream>
#include<cstdio>
using namespace std;
const int N=20005;
int n,m,p,q;
int afa[N],bfa[N];
inline int afind(int x){
	if(afa[x]!=x) afa[x]=afind(afa[x]);
	return afa[x];
}
inline int bfind(int x){
	if(bfa[x]!=x) bfa[x]=bfind(bfa[x]);
	return bfa[x];
}
int main(){
	scanf("%d%d%d%d",&n,&m,&p,&q);
	for(int i=1;i<=n;++i) afa[i]=i;
	for(int i=1;i<=m;++i) bfa[i]=i;
	for(int i=1;i<=p;++i){
		int x,y;
		scanf("%d%d",&x,&y);
		if(afind(x)!=afind(y)) afa[afa[x]]=afa[y];
	}
	for(int i=1;i<=q;++i){
		int x,y;
		scanf("%d%d",&x,&y);
		x=-x;
		y=-y;
		if(bfind(x)!=bfind(y)) bfa[bfa[x]]=bfa[y];
	}
	int jostar=afind(1);
	int dio=bfind(1);
	int a=0,b=0;
	for(int i=1;i<=n;++i)
		if(afind(i)==jostar) ++a;
	for(int i=1;i<=m;++i)
		if(bfind(i)==dio) ++b;
	printf("%d\n",min(a,b));
	return 0;
}

原文地址:https://www.cnblogs.com/648-233/p/12628884.html

时间: 2024-10-10 14:51:16

并查集刷题整理的相关文章

G - Brain Network (easy)(并查集水题)

G - Brain Network (easy) Time Limit:2000MS     Memory Limit:262144KB     64bit IO Format:%I64d & %I64u CodeForces 690C1 Description One particularly well-known fact about zombies is that they move and think terribly slowly. While we still don't know

poj 1182 食物链 并查集好题

挑战程序设计上有解答的并查集好题.把事件作为元素进行合并,举例:若输入1 2 3,意思就是把2,3归为同一类,至于归于哪一类并不需要去讨论,则把2属于A,3属于A这两件事件归为一类;2属于B,3属于B这两件事归为一类;2属于C,3属于C这两件事归为一类:若输入 2 2 3,由于A吃B,B吃C,C吃A,就把2属于A,3属于B这两件事情归为一类:以此类推.当检测到当前情况与之前正确的情况不符合,则错误的情况数加1. #include <iostream> #include <cstdio&g

【HDU1232】畅通工程(并查集基础题)

裸敲并查集,很水一次AC 1 #include <iostream> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cstdio> 5 #include <cctype> 6 #include <cmath> 7 #include <algorithm> 8 #include <numeric> 9 #include <string> 1

【HDU1856】More is better(并查集基础题)

裸并查集,但有二坑: 1.需要路径压缩,不写的话会TLE 2.根据题目大意,如果0组男孩合作的话,应该最大的子集元素数目为1.所以res初始化为1即可. 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <cstdlib> 5 #include <algorithm> 6 #include <numeric> 7 #include <

【HDU1325】Is It A Tree?(并查集基础题)

有以下坑点: 1.结束输入不一定-1,题目中的叙述只是说所有权值都为正值. 2.是否构成一棵树不能只判断是否只有一个根节点,没有环路,而且还需要判断每个节点的入度一定是1,不然就不是一棵树. (无环路也可用树的性质:结点数 = 边树 + 1 来取代) 1 #include <iostream> 2 #include <cstdlib> 3 #include <cstring> 4 #include <cctype> 5 #include <cmath&

UVALive 4487 Exclusive-OR 加权并查集神题

已知有 x[0-(n-1)],但是不知道具体的值,题目给定的信息 只有 I P V,说明 Xp=V,或者 I P Q V,说明 Xp ^ Xq=v,然后要求回答每个询问,询问的是 某任意的序列值 Xp1^Xp2,,,,X^pk 这个题目用加权并查集是这么处理的: 1. f[]照样是代表父节点,照样进行路径压缩,把每个 V[i]=V[i]^V[f[i]],即节点存储的值实际是它与它父亲的异或的值.为什么要这样呢,因为异或首先满足交换律,而且异或同一个数偶数次,即相当于本身,那么这个题目的其中一个要

【HDU2120】Ice_cream&#39;s world I(并查集基础题)

查环操作,裸题.一次AC. 1 #include <iostream> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cctype> 5 #include <cmath> 6 #include <string> 7 #include <cstdio> 8 #include <algorithm> 9 #include <numeric>

POJ2236 wireless network 【并查集水题】

前端开发whqet,csdn,王海庆,whqet,前端开发专家 今天是个好日子,2014年5月20日,表白的最佳时机,虽说孩子已经四岁.结婚已经五年,但是也不可以偷懒,于是有了这个效果. 在线研究点这里,下载收藏点这里.程序猿and程序媛,大胆秀出你的爱吧. 利用html5 canvas实现动态的文字粒子效果,效果如下. OK,简单看看原理,首先我们需要在canvas里面实现描边文字,然后利用getImageData获得描边文字的像素矩阵,将粒子效果绑定在描边文章上. 整个效果如下. html文

【HDU1231】How Many Tables(并查集基础题)

什么也不用说,并查集裸题,直接盲敲即可. 1 #include <iostream> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cstdio> 5 #include <cctype> 6 #include <cmath> 7 #include <algorithm> 8 #include <numeric> 9 using namespace s