本题应先使用并查集数出有多少 个集合,在删掉一个点后如果有一个集合因此分成了两个集合,即连通性被破坏。此时的新集合数一定大于原来的集合数,因为有个集合一分为二。对于删除点的方法这里直接使用重建并查集的方法,即如果删除1号点的话则在重建时把包含1号点的两个点不进行连接,再去数此时集合的数量。这样就相当与删除了1号点。
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <cstring>
using namespace std;
int n, m, cnt;
//建立结构体保存所有需要连接的两个点,方便后边重建
struct node
{
int u, v;
} e[5005];
//vist数组用来保存被删掉的点,如果要连接的两个点有vist保存的数那么就不连接
//以此来模拟该点被删除
int vist[550], fa[550];
int find(int k)
{
if (fa[k] != k) {
int p = k;
k = find(fa[k]);
fa[p] = k;
}
return k;
}
void connect(int a, int b)
{
a = find(a);
b = find(b);
fa[a] = b;
return;
}
int main()
{
int k;
int u, v;
cin >> n >> m;
//初始化集合
for (int i = 0; i < n; i++)
fa[i] = i;
for (int i = 0; i < m; i++)
{
cin >> u >> v;
//保存所有需要连接的两个点
e[i].u = u, e[i].v = v;
connect(u, v);
}
int num = 0, num1;
//数出初始的集合数
for (int i = 0; i < n; i++)
{
if (fa[i] == i)
{
num++;
}
}
cin>>k;
while (k--)
{
num1 = 0;
//初始化集合要在去掉点后重建
for (int i = 0; i < n; i++)
fa[i] = i;
int x;
cin>>x;
//标记x为去掉的点,并计数删掉点的个数,方便判断gameover
vist[x] = 1;
cnt++;
for (int i = 0; i < m; i++)
{
//跳过被删除的点
if (vist[e[i].u] == 1 || vist[e[i].v] == 1)
continue;
else
connect(e[i].u, e[i].v);
}
//再次数出(删除点后)有多少个集合
for (int i = 0; i < n; i++)
if (fa[i] == i)
num1++;
num1 -= cnt;//剪掉被删掉的点,因为被删掉后变成了一个单独的集合
if (num1<=num)
printf("City %d is lost.\n", x);
else
printf("Red Alert: City %d is lost!\n", x);
num = num1;
}
if (cnt == n)
printf("Game Over.");
return 0;
}