并查集 - 红色警报 - 天梯赛 L2-013
题意:
给 定 一 个 n 个 点 m 条 边 的 无 向 图 , 给定一个n个点m条边的无向图, 给定一个n个点m条边的无向图,
接 着 进 行 k 次 操 作 , 每 次 去 除 图 中 的 一 个 点 , 判 断 这 个 点 是 否 是 该 点 所 在 连 通 块 的 割 点 。 接着进行k次操作,每次去除图中的一个点,判断这个点是否是该点所在连通块的割点。 接着进行k次操作,每次去除图中的一个点,判断这个点是否是该点所在连通块的割点。
输入:
首 行 两 个 正 整 数 n 和 m , 首行两个正整数n和m, 首行两个正整数n和m,
接 着 m 行 , 每 行 分 别 包 含 两 个 整 数 , 表 示 一 条 边 的 两 个 端 点 接着m行,每行分别包含两个整数,表示一条边的两个端点 接着m行,每行分别包含两个整数,表示一条边的两个端点
然 后 一 个 正 整 数 k , 然后一个正整数k, 然后一个正整数k,
最 后 一 行 为 k 个 整 数 , 按 照 次 序 移 除 每 个 点 。 最后一行为k个整数,按照次序移除每个点。 最后一行为k个整数,按照次序移除每个点。
输出:
若 当 前 移 除 的 点 a i 不 是 该 点 所 在 连 通 块 的 割 点 , 则 输 出 : 若当前移除的点a_i不是该点所在连通块的割点,则输出: 若当前移除的点ai不是该点所在连通块的割点,则输出:City ai is lost.
否 则 输 出 : 否则输出: 否则输出:Red Alert: City ai is lost!
注意: 当 图 中 的 n 个 点 都 被 移 除 后 , 要 输 出 : 当图中的n个点都被移除后,要输出: 当图中的n个点都被移除后,要输出:Game Over.
Game Over. 的 条 件 是 n 个 点 都 被 移 除 , 而 非 完 成 k 次 操 作 。 这 里 是 本 题 一 个 坑 点 。 的条件是n个点都被移除,而非完成k次操作。这里是本题一个坑点。 的条件是n个点都被移除,而非完成k次操作。这里是本题一个坑点。
输入样例:
5 4
0 1
1 3
3 0
0 4
5
1 2 0 4 3
输出样例:
City 1 is lost.
City 2 is lost.
Red Alert: City 0 is lost!
City 4 is lost.
City 3 is lost.
Game Over.
数据范围: N(0 < N ≤ 500)和M(≤ 5000),分别为城市个数(于是默认城市从0到N-1编号)和连接两城市的通路条数。
分析:
看 这 个 数 据 范 围 , 可 以 暴 力 ( 乱 搞 ) 看这个数据范围,可以暴力(乱搞) 看这个数据范围,可以暴力(乱搞)
如 果 一 个 点 是 割 点 , 那 么 把 这 个 点 独 立 出 来 之 后 , 整 个 图 中 连 通 块 的 数 量 至 少 增 加 2. 如果一个点是割点,那么把这个点独立出来之后,整个图中连通块的数量至少增加2. 如果一个点是割点,那么把这个点独立出来之后,整个图中连通块的数量至少增加2.
接 下 来 的 问 题 就 是 如 何 用 统 计 连 通 块 的 数 量 。 接下来的问题就是如何用统计连通块的数量。 接下来的问题就是如何用统计连通块的数量。
利 用 并 查 集 统 计 连 通 块 的 数 量 , 判 断 条 件 : F i n d ( i ) = = i , 也 就 是 统 计 根 的 数 量 。 利用并查集统计连通块的数量,判断条件:Find(i)==i,也就是统计根的数量。 利用并查集统计连通块的数量,判断条件:Find(i)==i,也就是统计根的数量。
我 们 每 次 独 立 一 个 点 以 后 , 对 新 图 再 用 并 查 集 合 并 , 重 新 统 计 连 通 块 的 数 量 , 我们每次独立一个点以后,对新图再用并查集合并,重新统计连通块的数量, 我们每次独立一个点以后,对新图再用并查集合并,重新统计连通块的数量,
然 后 用 上 一 次 统 计 的 连 通 块 数 量 c n t 与 本 次 统 计 的 连 通 块 数 量 c n t 1 作 差 , 判 断 。 然后用上一次统计的连通块数量cnt与本次统计的连通块数量cnt1作差,判断。 然后用上一次统计的连通块数量cnt与本次统计的连通块数量cnt1作差,判断。
可 以 用 一 个 b o o l 数 组 把 新 独 立 出 的 点 标 记 出 来 , 合 并 的 时 候 过 滤 到 包 含 这 些 点 的 边 。 可以用一个bool数组把新独立出的点标记出来,合并的时候过滤到包含这些点的边。 可以用一个bool数组把新独立出的点标记出来,合并的时候过滤到包含这些点的边。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<cmath>
#include<set>
#include<map>
#include<vector>
#define P pair<int,int>
#define u first
#define v second
#define ll long long
using namespace std;
const int N = 510, M = 5010;
int n, m, k;
int p[N];
P E[M];
int cnt, cnt1;
bool st[N];
void Init()
{
for(int i=1;i<=n;i++) p[i]=i;
}
int Find(int x)
{
if(p[x]!=x) p[x]=Find(p[x]);
return p[x];
}
void unite(int a,int b)
{
a=Find(a), b=Find(b);
p[a]=b;
}
int main()
{
scanf("%d%d",&n,&m);
Init();
for(int i=0;i<m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
u++, v++;
E[i]={u,v};
unite(u,v);
}
for(int i=1;i<=n;i++)
if(Find(i)==i)
cnt++;
scanf("%d",&k);
for(int i=1;i<=k;i++)
{
int t;
scanf("%d",&t);
t++;
Init();
st[t]=true;
for(int j=0;j<m;j++)
{
int u=E[j].u, v=E[j].v;
if(st[u]||st[v]) continue;
unite(u,v);
}
for(int j=1;j<=n;j++)
if(Find(j)==j)
cnt1++;
if(cnt1-cnt>1) printf("Red Alert: City %d is lost!\n",t-1);
else printf("City %d is lost.\n",t-1);
cnt=cnt1;
cnt1=0;
if(i==n)
{
puts("Game Over.");
break;
}
}
return 0;
}