【C++/并查集】加边的无向图

161 阅读1分钟

题目描述

给你一个 n 个点,m 条边的无向图,求至少要在这个的基础上加多少条无向边使得任意两个点可达~ 

输入描述:

第一行两个正整数 n 和 m 。
接下来的m行中,每行两个正整数 i 、 j ,表示点i与点j之间有一条无向道路。

输出描述:

输出一个整数,表示答案

示例1

输入

4 2
1 2
3 4

输出

1

备注:

对于100%的数据,有n,m<=100000。

思路

对于有n个点的无向图来说,边的个数最多有n-1条,所以我只要检测每次输入的两个点是否能够构成集合,如果可以,那边的个数就要减一。

并查集两个函数的模板

for (int i = 1; i <= n; i++)
	set[i] = i;

int findx(int x)//寻找x的父节点(寻找x的boss)
{
	int r = x;
	while (r != set[r])
	{
		r = set[r];
	}
	return r;
}

bool merge(int x, int y)//将x和y构成集合(将x和y组成父子节点)
{
	int x1 = findx(x);
	int y1 = findx(y);
	if (y1 != x1)
	{
		set[y1] = x1;
		return true;
	}
	return false;
}

//优化的merge
for(int i=1;i<=m;i++)//x和y为两个节点  father为记录某元素的父节点(与上方的set一致)
{
       cin>>x>>y;
       father[find(x)]=find(y);
}

AC代码

#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <queue>
using namespace std;

const int maxn = 100005;
int set[maxn];

int findx(int x)
{
	int r = x;
	while (r != set[r])
	{
		r = set[r];
	}
	return r;
}

bool merge(int x, int y)
{
	int x1 = findx(x);
	int y1 = findx(y);
	if (y1 != x1)
	{
		set[y1] = x1;
		return true;
	}
	return false;
}

int main()
{
	int n, m;
	int ans;
	cin >> n >> m;
	ans = n - 1;

	for (int i = 1; i <= n; i++)
		set[i] = i;


	for (int i = 0; i < m; i++)
	{
		int p, q;
		cin >> p >> q;
		if (merge(p, q))
		{
			ans--;
			//cout << p<<q << endl;
		}

	}
	cout << ans << endl;
	return 0;
}

//2022.4.24 并查集模板