【题目链接】
【题目考点】
1. 图论:无向图连通性
2. 并查集
【解题思路】
这是个无向图,每个城镇是一个顶点,每条道路是一条边。“任何两个城镇间都可以实现交通”,即为任意两顶点间有路径。
当前该图未必是连通图,问想让该图变为连通图最少还需要添加多少条边。
显然,需要添加边的条数为该图中连通分量的数量减1。
求一个图的连通分量数量,有两种方法
解法1:搜索
尝试从每个顶点出发进行搜索,可以进行深搜或广搜,标记访问过的顶点。成功开始搜索的次数即为连通分量的个数。
解法2:并查集
每个连通分量是一个集合,遍历所有的边,让每条边连接的两个顶点所在的集合合并。最后集合的数量即为连通分量的数量。
图中可能有重边,但不影响这两种解法。
【题解代码】
解法1:搜索
- 深搜
#include <bits/stdc++.h>
using namespace std;
#define N 1005
vector<int> edge[N];
int n, m, ct;//ct:连通分量数量
bool vis[N];
void init()//变量清零
{
for(int i = 1; i <= n; ++i)
edge[i].clear();
ct = 0;
memset(vis, 0, sizeof(vis));
}
void dfs(int u)
{
for(int v : edge[u])
{
if(vis[v] == false)
{
vis[v] = true;
dfs(v);
}
}
}
int main()
{
int f, t;
while(cin >> n >> m && n != 0)
{
init();
for(int i = 1; i <= m; ++i)
{
cin >> f >> t;
edge[f].push_back(t);
edge[t].push_back(f);
}
for(int u = 1; u <= n; ++u)
{
if(vis[u] == false)
{
vis[u] = true;
ct++;
dfs(u);
}
}
cout << ct-1 << endl;//添加连通分量数量减1的边,就可以让整个图变为连通图
}
return 0;
}
- 广搜
#include <bits/stdc++.h>
using namespace std;
#define N 1005
vector<int> edge[N];
int n, m, ct;//ct:连通分量数量
bool vis[N];
void init()//变量清零
{
for(int i = 1; i <= n; ++i)
edge[i].clear();
ct = 0;
memset(vis, 0, sizeof(vis));
}
void bfs(int sv)
{
queue<int> que;
que.push(sv);
while(que.empty() == false)
{
int u = que.front();
que.pop();
for(int v : edge[u])
{
if(vis[v] == false)
{
vis[v] = true;
que.push(v);
}
}
}
}
int main()
{
int f, t;
while(cin >> n >> m && n != 0)
{
init();
for(int i = 1; i <= m; ++i)
{
cin >> f >> t;
edge[f].push_back(t);
edge[t].push_back(f);
}
for(int u = 1; u <= n; ++u)
{
if(vis[u] == false)
{
vis[u] = true;
ct++;
bfs(u);
}
}
cout << ct-1 << endl;//添加连通分量数量减1的边,就可以让整个图变为连通图
}
return 0;
}
解法2:并查集
#include<bits/stdc++.h>
using namespace std;
#define N 1005
int fa[N];
void init(int n)
{
for(int i = 1; i <= n; ++i)
fa[i] = i;
}
int find(int x)
{
if(x == fa[x])
return x;
else
return fa[x] = find(fa[x]);
}
void merge(int x, int y)
{
fa[find(x)] = find(y);
}
int main()
{
int n, m, f, t, ct;
while(cin >> n >> m && n != 0)
{
init(n);//初始化fa数组
ct = 0;//连通分量的个数
for(int i = 1; i <= m; ++i)
{
cin >> f >> t;
merge(f, t);
}
for(int i = 1; i <= n; ++i)
if(fa[i] == i)
ct++;
cout << ct-1 << endl;//把ct个连通分量连成连通图,还需要ct-1条边
}
return 0;
}