PTA-L2-013 红色警报 (25分)

19 篇文章 0 订阅

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;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

娃娃酱斯密酱

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值