题目链接
思路:利用并查集,每次删完结点,统计连通块,如果比原来多了1块及以上,则说明出现连通块分裂,该节点对其他节点有影响,因为我在题目中统计连通块的方式是遍历对于所有结点的root数组,是-1则连通块加一,但删除该点后还是会统计到这个点为连通块,故题目中的判断是删后连通块>原连通块+1。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAX = 5e2+5;
int root[MAX];
bool _map[MAX][MAX];
bool vis[MAX];
int N, M;
int find_root(int x) {
return root[x] < 0 ? x : root[x] = find_root(root[x]);
}//优化版并查集,会将该节点并到最深入的那个根上
void union_root(int a, int b) {
a = find_root(a);
b = find_root(b);
if (a != b) {
if (root[a] < root[b]) {
root[a] += root[b];
root[b] = a;
}
else{
root[b] += root[a];
root[a] = b;
}
}
}
//将root数组置为-1,负数代表该节点的子节点个数
void init(int N) {
for (int i = 0; i < N; i++)
root[i] = -1;
}
int main() {
int original=0,after=0;
scanf("%d%d", &N, &M);
int v, t;
init(N);
for (int i = 0; i < M; i++) {
scanf("%d%d", &v, &t);
_map[v][t] = 1;
_map[t][v] = 1;
union_root(v, t);
}
int K,edge;
for (int i = 0; i < N; i++)
if (root[i] < 0)
original++;
scanf("%d",& K);
int k = K;
while (k--) {
scanf("%d", &edge);
init(N);
for (int i = 0; i < N; i++) {//与该点相连的边删去
_map[i][edge] = 0;
_map[edge][i] = 0;
}
for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++)
if (_map[i][j])
union_root(i, j);
for (int i = 0; i < N; i++)
if (root[i] < 0)
after++;
if (after>original+1)
printf("Red Alert: City %d is lost!\n",edge);
else
printf("City %d is lost.\n", edge);
original = after;
after = 0;
}
if (K == N)
printf("Game Over.");
}