战争中保持各个城市间的连通性非常重要。本题要求你编写一个报警程序,当失去一个城市导致国家被分裂为多个无法连通的区域时,就发出红色警报。注意:若该国本来就不完全连通,是分裂的k个区域,而失去一个城市并不改变其他城市之间的连通性,则不要发出警报。
输入格式:
输入在第一行给出两个整数N(0 < N ≤ 500)和M(≤ 5000),分别为城市个数(于是默认城市从0到N-1编号)和连接两城市的通路条数。随后M行,每行给出一条通路所连接的两个城市的编号,其间以1个空格分隔。在城市信息之后给出被攻占的信息,即一个正整数K和随后的K个被攻占的城市的编号。
注意:输入保证给出的被攻占的城市编号都是合法的且无重复,但并不保证给出的通路没有重复。
输出格式:
对每个被攻占的城市,如果它会改变整个国家的连通性,则输出Red Alert: City k is lost!,其中k是该城市的编号;否则只输出City k is lost.即可。如果该国失去了最后一个城市,则增加一行输出Game Over.。
输入样例:
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.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
//** Class for buffered reading int and double values *//*
class Reader {
static BufferedReader reader;
static StringTokenizer tokenizer;
// ** call this method to initialize reader for InputStream *//*
static void init(InputStream input) {
reader = new BufferedReader(new InputStreamReader(input));
tokenizer = new StringTokenizer("");
}
// ** get next word *//*
static String next() throws IOException {
while (!tokenizer.hasMoreTokens()) {
// TODO add check for eof if necessary
tokenizer = new StringTokenizer(reader.readLine());
}
return tokenizer.nextToken();
}
static boolean hasNext()throws IOException {
return tokenizer.hasMoreTokens();
}
static String nextLine() throws IOException{
return reader.readLine();
}
static char nextChar() throws IOException{
return next().charAt(0);
}
static int nextInt() throws IOException {
return Integer.parseInt(next());
}
static float nextFloat() throws IOException {
return Float.parseFloat(next());
}
}
public class Main {
static int[] pre = new int[500];
static int[] vis = new int[500];
static Edge []edges = new Edge[5000];
public static void main(String[] args) throws IOException {
Reader.init(System.in);
int n = Reader.nextInt();
int m = Reader.nextInt();
int u,v;
for (int i = 0; i < n; i++) {
pre[i] = i;
}
for (int i = 0; i < m; i++) {
edges[i] = new Edge();
u = Reader.nextInt();
v = Reader.nextInt();
edges[i].x = u;
edges[i].y = v;
join(u,v);//将这条边的两个点合并到一个连通分支上
}
int sum = 0;//独立顶点
for (int i = 0; i < n; i++) {
if (i==pre[i]) {
sum++;
}
}
int k = Reader.nextInt();
for (int i = 0; i < k; i++) {
//每次被攻击前先初始化并查集
for (int j = 0; j < n; j++) {
pre[j] = j;
}
//被攻击后标记被攻击的城市
int attackedCity = Reader.nextInt();
vis[attackedCity] = 1;
//遍历所有边,如果某一条边的两个顶点包含被攻击顶点就不把这条边的两个顶点合并
for (int j = 0; j < m; j++) {
if (vis[edges[j].x]==1||vis[edges[j].y]==1) {
continue;
}
join(edges[j].x,edges[j].y);
}
int cnt = 0;//更新后的独立顶点数
for (int j = 0; j < n; j++) {
if (pre[j]==j) {
cnt++;
}
}
// 如果独立顶点数和原来一样说明,被攻击的顶点本来就是独立的,那么对于连通分支数没有影响;如果独立顶点数比原来大1,说明被攻击的顶点原来在某一连通分支上的边缘,被攻击后对于连通分支数仍然没有影响但是独立顶点数会增大1
if(cnt-1 == sum||cnt ==sum) {
System.out.println("City "+attackedCity+" is lost.");
// 如果独立顶点数增大了不止1个,说明被攻击顶点在原来连通分支的中间,此时连通分支数会增加
}else {
System.out.println("Red Alert: City "+attackedCity+" is lost!");
}
sum = cnt;
}
// 被攻击顶点数比顶点数还多那就Game Over了
if (k>=n) {
System.out.println("Game Over.");
}
}
static int find(int x) // 查找根节点
{
int r = x;
while (pre[r] != r) // 返回根节点 r
r = pre[r];
int i = x, j;
while (i != r) // 路径压缩
{
j = pre[i]; // 在改变上级之前用临时变量 j 记录下他的值
pre[i] = r; // 把上级改为根节点
i = j;
}
return r;
}
static void join(int x, int y) // 判断x y是否连通,
// 如果已经连通,就不用管了 如果不连通,就把它们所在的连通分支合并起,
{
int fx = find(x), fy = find(y);
if (fx != fy)
pre[fx] = fy;
}
static class Edge{
int x;
int y;
}
}