这是一道并查集问题,需要注意的是,并不是所有的点都进行并查集操作,而是除了“某点”之外其余各点均进行合并,然后输出合并后集合的个数-1
// runtime: 4ms
// space: 512K
// https://pintia.cn/problem-sets/994805342720868352/problems/994805500414115840
#include <cstdio>
#include <vector>
using namespace std;
const int MAX = 1000;
vector<int> graph[MAX];
int father[MAX];
int height[MAX];
void Init() { // 初始化
for (int i = 0; i < MAX; ++i) {
father[i] = i;
height[i] = 1;
}
}
int Find(int x) { // 查找
if (x != father[x]) {
father[x] = Find(father[x]); // 优化高度
}
return father[x];
}
void Union(int a, int b) { // 合并
a = Find(a);
b = Find(b);
if (height[a] < height[b]) {
father[a] = b;
} else if (height[a] > height[b]) {
father[b] = a;
} else {
father[b] = a;
height[a]++;
}
}
int BuildUnion(int n, int except) { // 主要逻辑
Init();
int count = 0;
for (int i = 1; i <= n; ++i) {
for (int j = 0; j < graph[i].size(); ++j) { // 除了except的点,其余全部进行并查集
if (i == except || graph[i][j] == except)
continue;
Union(i, graph[i][j]);
}
}
for (int i = 1; i <= n; ++i) {
if (i == except)
continue;
if (father[i] == i)
count++; // count指一共有多少个集合
}
return count - 1; // 输出count - 1即所需要最少的路
}
int main() {
int N, M, K;
scanf("%d %d %d", &N, &M, &K);
Init();
while (M--) {
int c1, c2;
scanf("%d %d", &c1, &c2);
graph[c1].push_back(c2);
graph[c2].push_back(c1);
}
while (K--) {
int c;
scanf("%d", &c);
printf("%d\n", BuildUnion(N, c));
}
return 0;
}

京公网安备 11010502036488号