题目大意
给出n个城市之间有相互连接的m条道路,当删除一个城市和其连接的道路的时候,问其他几个剩余的城市至少要添加多少个路线才能让它们重新变为连通图。
思路
添加的最少的路线,就是他们的连通分量数-1,因为当a个互相分立的连通分量需要变为连通图的时候,只需要添加a-1个路线,就能让他们相连。所以这道题就是求去除了某个结点之后其他的图所拥有的连通分量数。 使用邻接表存储(也可以用邻接矩阵),对于每一个被占领的城市,去除这个城市结点,就是把它标记为已经访问过,这样在遍历的时候,对于所有未访问的结点进行遍历,就会跳过那个城市,最终求出所有的连通分量的个数。 注意:因为有很多个要判断的数据,每一次输入被占领的城市之前要把visit数组置为false。
AC代码
用了深度优先遍历和广度优先遍历来写,除了遍历核心代码(即函数DFS(int x)和BFS(int x))之外其余代码都完全相同。深度优先遍历写起来更方便些。
DFS
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<vector>
using namespace std;
#define MAX 1002
vector<int>Adj[MAX];
bool vis[MAX] = { false };
int M, N, K;
void DFS(int x) {
vis[x] = true;
for (int i = 0; i < Adj[x].size(); i++)
if (vis[Adj[x][i]] == false)
DFS(Adj[x][i]);
}
int Trave(int s) {
int i, times = 0;
fill(vis, vis + N + 1, false);
vis[s] = true;
for (i = 1; i <= N; i++) {
if (vis[i] == false) {
DFS(i);
times++;
}
}
return times;
}
int main() {
int i, temp, a, b;
scanf("%d%d%d", &N, &M, &K);
for (i = 0; i < M; i++) {
scanf("%d%d", &a, &b);
Adj[a].push_back(b);
Adj[b].push_back(a);
}
for (i = 0; i < K; i++) {
scanf("%d", &temp);
printf("%d\n", Trave(temp) - 1);
}
return 0;
}
BFS
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<queue>
#include<vector>
using namespace std;
#define MAX 1002
#define INF 10000000
vector<int>Adj[MAX];
bool vis[MAX] = { false };
int M, N, K;
int BFS(int x) {
int ans = 1;
queue<int>q;
q.push(x);
vis[x] = true;
while (!q.empty()) {
int t = q.front();
for (int i = 0; i < Adj[t].size(); i++) {
int v = Adj[t][i];
if (vis[v] == false) {
q.push(v);
vis[v] = true;
}
}
q.pop();
}
return ans;
}
int Trave(int s) {
int i, times = 0;
fill(vis, vis + N + 1, false);
vis[s] = true;
for (i = 1; i <= N; i++) {
if (vis[i] == false) {
BFS(i);
times++;
}
}
return times;
}
int main() {
int i, temp, a, b;
scanf("%d%d%d", &N, &M, &K);
for (i = 0; i < M; i++) {
scanf("%d%d", &a, &b);
Adj[a].push_back(b);
Adj[b].push_back(a);
}
for (i = 0; i < K; i++) {
scanf("%d", &temp);
printf("%d\n", Trave(temp) - 1);
}
return 0;
}