这是一道并查集问题,需要注意的是,并不是所有的点都进行并查集操作,而是除了“某点”之外其余各点均进行合并,然后输出合并后集合的个数-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; }