并查集板子+kruskal

最近在学最小生成树得时候又用到了并查集,一起来整理一下

1.并查集

并查集就是字面意思,将两个单独得集合合并成一个大的集合。

并查集关键在于两个操作:合并和查找

先要完成查找操作(合并操作在查找的基础上)

int find(int x)
{
    return root[x] == x ? x : root[x]=find(root[x]);
}

查找x个体所在的根结点,从而确定集合关系 ,find函数缩短路径 ,把一个集合中所有元素都指向一个根结点,减少树的高度 ,如果x的根结点root[x]为自己则返回x,如果不是x的根结点root[x]=root[x]的根节点递归找到那个共同的根。

最后就是合并操作

void add(int x,int y)
{
  int n=find(x);
  int m=find(y);
  if(n!=m) root[n]=m;
}

合并操作先检查两者是否已经在同一集合,如果不在同一集合(不为相同的根节点)则把两元素的根结点相连达到合并目的,两集合合并成同一集合。

2.kruskal板子 最小生成树

kruskal是把图的边视为集合中的元素,用贪心思想,把边的权值从小到大遍历,找到n-1条边连接n个节点,最重要的是 防止集合中的边形成环导致不为最小生成树

来自洛谷 :P3366最小生成树板子

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <string>
#include <map>
#include <cmath>
#include <set>
#include <queue>
#define ri  int

typedef int ll;
typedef long long lll;
using namespace std;

const long long mod=1e9+7;

ll n,m;
ll p[200005];   //root数组
struct e{
	ll f;
	ll e;
	ll w;  //权值
}a[200005];   //边集合

bool cmp(e a,e b)
{
	return a.w<b.w;
}

ll find(ll x)    //查
{
	return p[x] == x ? x : p[x]=find(p[x]);
}


int main()
{   
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin >> n >> m;
	for(ri i=1;i<=m;++i)
		cin >> a[i].f >> a[i].e >> a[i].w;
	for(ri i=1;i<=n;++i) p[i]=i;
	sort(a+1,a+1+m,cmp);   //按照权值排序从小到大
	
	ll l,r;
	ll ans=0;
	for(ri i=1;i<=m;++i)
	{
		l=find(a[i].f);
		r=find(a[i].e);
		if(l!=r)        //合并
		{
			ans+=a[i].w;
			p[l]=r;
		}
	}
	cout << ans << '\n';
    return 0;
}
posted @ 2021-05-20 11:08  gonghw403  阅读(56)  评论(0编辑  收藏  举报