题目:
分析:
该题使用并查集来解决,通过判断去除 某一个城市 之前和之后的连通性得出是否要发出警报
每一次攻占某一个城市之前,求出根节点的个数ans,攻占城市之后,标记该城市,然后对未标记的城市做一遍并查集,判断此时的根节点一共有cnt个,如果 cnt 等于 ans ,说明此时破坏的城市并没有使连通性发生变化,如果cnt <ans说明,此时破坏的城市为孤立城市,也不会发出警报,在cnt > ans 说明破坏了原有的连通性,需要发出警报。
代码:
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int MAXN = 505;
int root[MAXN],n,m,k,ans;
bool vis[MAXN];
struct node
{
int x,y;
}no[5005];
int getr(int x)
{
if(root[x] == x) return x;
else return root[x] = getr(root[x]);
}
void Union(int x,int y)
{
int xx = getr(x);
int yy = getr(y);
if(xx != yy)
root[xx] = yy;
}
int main()
{
int city;
scanf("%d%d",&n,&m);
for(int i=0;i<n;++i)
root[i] = i;
for(int i=1;i<=m;++i)
{
scanf("%d%d",&no[i].x,&no[i].y);
Union(no[i].x,no[i].y);
}
for(int i=0;i<n;++i)
if(root[i]==i) ans++;
scanf("%d",&k);
while(k--)
{
int cnt = 0;
scanf("%d",&city);
vis[city] = true;
for(int i=0;i<n;++i)
root[i] = i;
for(int i=1;i<=m;++i)
if(!vis[no[i].x] && !vis[no[i].y])
Union(no[i].x,no[i].y);
for(int i=0;i<n;++i)
if(!vis[i]&&root[i]==i) cnt++;
if(cnt <= ans)
printf("City %d is lost.\n",city);
else
printf("Red Alert: City %d is lost!\n",city);
ans = cnt;
if(ans == 0)
{
printf("Game Over.\n");
return 0;
}
}
return 0;
}