Problem Description
It is vitally important to have all the cities connected by highways in a war. If a city is occupied by the enemy, all the highways from/toward that city are closed. We must know immediately if we need to repair any other highways to keep the rest of the cities connected. Given the map of cities which have all the remaining highways marked, you are supposed to tell the number of highways need to be repaired, quickly.
For example, if we have 3 cities and 2 highways connecting c i t y 1 − c i t y 2 city_1 - city_2 city1−city2 and c i t y 1 − c i t y 3 city_1 - city_3 city1−city3# . Then if c i t y 1 city_1 city1 is occupied by the enemy, we must have 1 highway repaired, that is the highway c i t y 2 − c i t y 3 city_2 - city_3 city2−city3 .
Input Specification:
Each input file contains one test case. Each case starts with a line containing 3 numbers N (<1000), M and K, which are the total number of cities, the number of remaining highways, and the number of cities to be checked, respectively. Then M lines follow, each describes a highway by 2 integers, which are the numbers of the cities the highway connects. The cities are numbered from 1 to N. Finally there is a line containing K numbers, which represent the cities we concern.
Output Specification:
For each of the K cities, output in a line the number of highways need to be repaired if that city is lost.
Sample Input:
3 2 3
1 2
1 3
1 2 3
Sample Output:
1
0
0
Code Example(DFS, time-out)
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.*;
/**
* @author snowflake
* @create-date 2019-08-28 17:03
*/
public class Main {
public static void main(String[] args) throws IOException {
Reader.init(System.in);
int n = Reader.nextInt();
int m = Reader.nextInt();
int k = Reader.nextInt();
// 创建 n * n 的二维数组
int[][] cities = new int[n][n];
for (int i = 0; i < m; i++) {
int n1 = Reader.nextInt();
int n2 = Reader.nextInt();
cities[n1 - 1][n2 - 1] = 1;
cities[n2 - 1][n1 - 1] = 1;
}
for (int i = 0; i < k; i++) {
int index = Reader.nextInt();
// 然后判断该图有几个连通子图
System.out.println(method1(index - 1, cities) - 1);
}
}
public static int method1(int index, int[][] cities) {
int num = 0;
// 定义一个访问标记数组
boolean[] visited = new boolean[cities.length];
// 标记破坏点已经访问过
visited[index] = true;
// 开始遍历
for (int i = 0; i < cities.length; i++) {
if (!visited[i]) {
// 提前标记访问过,这样不同在 dfs 方法中跳过该点
visited[i] = true;
dfs(cities, i, visited);
num++;
}
}
return num;
}
private static void dfs(int[][] cities, int i, boolean[] visited) {
// 纠结为什么要从 j = 0 从头开始,明明是无向图,直接从 i + 1 开始即可,
// 但是忽略了一点,如果直接从 i + 1 开始的话,会失去部分指向关系,
// 导致一个无向图变成了一个有向图
// 如果是有向图,从不同的顶点进行遍历,得到的结果是不一样的
// 后来想了一下,是从第一行开始遍历的那么,左下角的元素肯定是访问过的,例如
// 0 1 1 1
// 1 0 1 1
// 1 1 0 1
// 1 1 1 0
// 这种情况下如果不从 0 开始遍历,是成功的但是
// 0 0 0 1
// 0 0 1 1
// 0 1 0 0
// 1 1 0 0
// 这种情况下,访问到 [0, 3] 会跳转到 第四行,但是第四行跟第二行还有指向关系,
// 但是如果不从 0 开始遍历的话,就无法取到这个指向关系了,那么会多出一个连通分支
for (int j = 0; j < cities.length; j++) {
if (!visited[j] && cities[i][j] == 1) {
visited[j] = true;
dfs(cities, j, visited);
}
}
}
static class Reader {
static BufferedReader reader;
static StringTokenizer tokenizer;
/**
* call this method to initialize reader for InputStream
*/
public static void init(InputStream input) {
reader = new BufferedReader(new InputStreamReader(input));
tokenizer = new StringTokenizer("");
}
public static String nextLine() throws IOException {
return reader.readLine();
}
/**
* get next word
*/
public static String next() throws IOException {
while (!tokenizer.hasMoreTokens()) {
tokenizer = new StringTokenizer(reader.readLine());
}
return tokenizer.nextToken();
}
public static int nextInt() throws IOException {
return Integer.parseInt(next());
}
public static double nextDouble() throws IOException {
return Double.parseDouble(next());
}
}
}
Code Example(DisjointUnionSets, time-out)
package xyz.snowflake.arithmetic.disjoint_set;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
/**
* @create-date 2019-08-29 22:10
*/
// A Java program to implement Disjoint Set Data
// Structure.
class DisjointUnionSets {
int[] rank, parent;
int n;
// Constructor
public DisjointUnionSets(int n) {
rank = new int[n];
parent = new int[n];
this.n = n;
makeSet();
}
// Creates n sets with single item in each
void makeSet() {
for (int i = 0; i < n; i++) {
// Initially, all elements are in
// their own set.
parent[i] = i;
}
}
// Returns representative of x's set
int find(int x) {
// Finds the representative of the set
// that x is an element of
if (parent[x] != x) {
// if x is not the parent of itself
// Then x is not the representative of
// his set,
parent[x] = find(parent[x]);
// so we recursively call Find on its parent
// and move i's node directly under the
// representative of this set
}
return parent[x];
}
// Unites the set that includes x and the set
// that includes x
void union(int x, int y) {
// Find representatives of two sets
int xRoot = find(x);
int yRoot = find(y);
// Elements are in the same set, no need
// to unite anything.
if (xRoot == yRoot)
return;
// If x's rank is less than y's rank
if (rank[xRoot] < rank[yRoot])
// Then move x under y so that depth
// of tree remains less
parent[xRoot] = yRoot;
// Else if y's rank is less than x's rank
else if (rank[yRoot] < rank[xRoot])
// Then move y under x so that depth of
// tree remains less
parent[yRoot] = xRoot;
// if ranks are the same
else {
// Then move y under x (doesn't matter
// which one goes where)
parent[yRoot] = xRoot;
// And increment the the result tree's
// rank by 1
rank[xRoot] = rank[xRoot] + 1;
}
}
}
public class Main {
static class Node {
int n1, n2;
public Node(int n1, int n2) {
this.n1 = n1;
this.n2 = n2;
}
}
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
int n = cin.nextInt();
int m = cin.nextInt();
int k = cin.nextInt();
List<Node> list = new ArrayList<>(n);
for (int i = 0; i < m; i++) {
int n1 = cin.nextInt();
int n2 = cin.nextInt();
list.add(new Node(n1 - 1, n2 - 1));
}
for (int i = 0; i < k; i++) {
int value = cin.nextInt();
List<Node> filterList = new ArrayList<>();
for (Node node : list) {
if (node.n1 != value - 1 && node.n2 != value - 1) {
filterList.add(node);
}
}
DisjointUnionSets dus = new DisjointUnionSets(n);
for (Node node : filterList) {
dus.union(node.n1, node.n2);
}
int count = 0;
for (int j = 0; j < n; j++) {
if (dus.find(j) == j) {
count++;
}
}
System.out.println(n == 1 ? 0 : count - 2);
}
}
}
Code Example(C++, success)
#include<cstdio>
#include<cstring>
int N, M, lost;
bool map[1000][1000], visited[1000];
void dfs(int start)
{
for(int i = 1; i <= N; ++i)
{
if(!visited[i] && map[start][i])
{
visited[i] = true;
dfs(i);
}
}
}
int main()
{
int K, c1, c2, cnt;
scanf("%d %d %d", &N, &M, &K);
for(int i = 0; i < M; ++i)
{
scanf("%d %d", &c1, &c2);
map[c1][c2] = map[c2][c1] = true;
}
for(int i = 0; i < K; ++i)
{
scanf("%d", &lost);
cnt = 0;
memset(visited, 0, sizeof(visited));
visited[lost] = true;
for(int j = 1; j<=N; ++j)
{
if(visited[j]==false)
{
++cnt;
dfs(j);
}
}
printf("%d\n", cnt-1);
}
return 0;
}