PTA-L2-013 红色警报 (25分)
这道题,并查集。
判断有多少个连通的区域,其实就是并查集的操作中判断有多少个根节点。
就是统计根节点的操作cnt。
我们最开始应该保存每一条连通的边。
在后面的攻占城市中,我们只需要不处理那些攻占城市连通的边即可。用vis[]记录。
其他的继续重新使用并查集合并操作,进而统计有多少个根节点sum。
判断两个的数量是否相等/相差1(原因是攻占一个城市之后,那个城市会消失,不算入我们连通性中,但是并查集数根节点的时候会计数,所以是相差1)
因为题目中提到如果本来一个国家的城市是分裂成了k个区域,失去一个城市不影响其他城市的连通性,就不发出警报。而且样例中的城市2就是这种情况,失去它不影响其他城市的连通性(因为城市2是孤立的个体)
所以会有相等的判断。
进而确定输出是什么。
然后更新我们的cnt,因为题目意思是在上一步操作中有没有改变连通性,而不是说对于原始的连通性而言。
最后判断我们的cnt/sum是否为n,如果为n代表所有城市都是孤立的个体,代表全部沦陷。对应输出即可。
代码部分:
#include <bits/stdc++.h>
#define mst(a, n) memset(a, n, sizeof(a))
using namespace std;
const int N = 5e3 + 10;
const int M = 55;
const int INF = 1e6 + 10;
typedef long long ll;
struct node
{
int u;
int v;
}e[N];
int n, m;
int fa[N];
int vis[N];
int find(int x)
{
if (x != fa[x])
{
return fa[x] = find(fa[x]);
}
return fa[x];
}
void merge(int x, int y)
{
int fax = find(x);
int fay = find(y);
if (fax != fay)
{
fa[fay] = fax;
}
}
int main()
{
cin >> n >> m;
for (int i = 0; i < n; i++)
{
fa[i] = i;
}
for (int i = 0; i < m; i++)
{
int x, y;
scanf ("%d%d", &x, &y);
e[i].u = x;
e[i].v = y;
merge(x, y);
}
int cnt = 0;
for (int i = 0; i < n; i++)
{
if (find(i) == i)
{
cnt++;
}
}
int k;
int sum = 0;
cin >> k;
while (k--)
{
int x;
cin >> x;
vis[x] = 1;
for (int i = 0; i < n; i++)
{
fa[i] = i;
}
for (int i = 0; i < m; i++)
{
if (vis[e[i].u] || vis[e[i].v])
{
continue;
}
else
{
merge(e[i].u, e[i].v);
}
}
sum = 0;
for (int i = 0; i < n; i++)
{
if (i == find(i))
{
sum++;
}
}
if (sum == cnt + 1 || sum == cnt)
{
printf ("City %d is lost.\n", x);
}
else
{
printf ("Red Alert: City %d is lost!\n", x);
}
cnt = sum;
}
if (sum == n)
{
cout << "Game Over.\n";
}
return 0;
}