1013 Battle Over Cities (25 分)
今天给大家分享PAT甲级的一道小题,考察点:图的遍历
简单翻译:
给你一个连通图,如果拿掉一个节点(与这个节点相连的边都消失了),最少需要再添加多少条边才能成为一个新的连通图
思路:
找连通分量:原图是属于一个连通分量,拿掉一个节点后,可能会分裂成多个连通分量,连通分量的个数减去1就是需要的边的个数。
如何找连通分量的个数:可选的思路有:
- 并查集
- 广度/深度优先搜索
- 拓扑排序
其实搜索和拓扑排序的思路差不多。这里为了方便,介绍深度优先搜索的方式。
使用深度优先搜索找连通分量个数的方式分为以下步骤:
- 找没有被访问的点,连通分量的个数加1
- 从这个点开始深度优先搜索,搜索完之后返回第一步
- 直到所有的点都被访问过,就求出来连通分量的个数。
针对这个题,稍微做了点儿优化。因为感觉纯暴力的搜索可能会过不去。所以是使用邻接链表来表示整个图,最后过了,没有试邻接矩阵会不会TL。感兴趣的读者可以尝试一下。
C++代码:
#include"bits/stdc++.h"
#define all(x) x.begin(),x.end()
#define len(x) x.size()
#define INF (1e9)
#define vi vector<int>
#define ll long long int
#define ull unsigned long long int
#define db double
#define vvi vector<vector<int>>
#define pb(x) push_back(x);
using namespace std;
vvi a(1001, vi(0));
int temp;
void dfs(vi& used, int k) {
int n = len(a[k]);
for (int i = 0; i < n; i++) {
if (used[a[k][i]] == 0 && a[k][i] != temp) {
used[a[k][i]] = 1;
dfs(used, a[k][i]);
}
}
}
int f(vi& used) {
int n = len(used);
int k = 0;
for (int i = 1; i < n; i++) {
if (used[i] == 0 && i != temp) {
k++;
used[i] = 1;
dfs(used, i);
}
}
return k;
}
int main() {
int N, M, K;
cin >> N >> M >> K;
for (int i = 0; i < M; i++) {
int t1, t2;
cin >> t1 >> t2;
a[t1].pb(t2);
a[t2].pb(t1);
}
for (int i = 0; i < K; i++) {
cin >> temp;
vi used(N + 1, 0);
cout << f(used) - 1 << endl;
}
return 0;
}