题目描述
给你一个 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 并查集模板