解法一:深度优先搜索

题目大意抽象:图中删除某个点和相关的边,求使得图连通所需要添加的最少边数。
使得图连通所需要添加的最少边数 = 独立连通分支数量 - 1
可以使用深度优先搜索的方法来计算独立连通分支的数量。

  1. import java.io.*;
  2. import java.util.*;
  3. public class Main {
  4. private static boolean[][] map;
  5. private static boolean[] isVisited;
  6. public static void main(String[] args) throws IOException {
  7. StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
  8. PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
  9. in.nextToken();
  10. int N = (int) in.nval;
  11. in.nextToken();
  12. int M = (int) in.nval;
  13. in.nextToken();
  14. int K = (int) in.nval;
  15. map = new boolean[N + 1][N + 1];
  16. for (int i = 0, u, v; i < M; ++i) {
  17. in.nextToken();
  18. u = (int) in.nval;
  19. in.nextToken();
  20. v = (int) in.nval;
  21. map[u][v] = map[v][u] = true;
  22. }
  23. for (int i = 0, city, ans; i < K; ++i) {
  24. isVisited = new boolean[N + 1];
  25. ans = 0;
  26. in.nextToken();
  27. city = (int) in.nval;
  28. isVisited[city] = true;
  29. for (int index = 1; index <= N; ++index) {
  30. if (!isVisited[index]) {
  31. ++ans;
  32. dfs(index);
  33. }
  34. }
  35. // 连通所需的路径数量 = 独立联通分支数量 - 1
  36. out.println(ans - 1);
  37. }
  38. out.flush();
  39. }
  40. private static void dfs(int city) {
  41. isVisited[city] = true;
  42. for (int i = 1; i < map.length; ++i) {
  43. if (map[city][i] && !isVisited[i]) {
  44. dfs(i);
  45. }
  46. }
  47. }
  48. }

解法二:并查集

也可以用并查集来统计独立连通分支数量,不过Java写的话最后一个测试点超时了😅。

  1. import java.io.*;
  2. import java.util.*;
  3. public class Main {
  4. private static int[] father;
  5. public static void main(String[] args) throws IOException {
  6. StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
  7. PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
  8. in.nextToken();
  9. int N = (int) in.nval;
  10. in.nextToken();
  11. int M = (int) in.nval;
  12. in.nextToken();
  13. int K = (int) in.nval;
  14. int[][] edges = new int[M][2];
  15. for (int i = 0; i < M; ++i) {
  16. in.nextToken();
  17. edges[i][0] = (int) in.nval;
  18. in.nextToken();
  19. edges[i][1] = (int) in.nval;
  20. }
  21. for (int i = 0, city, ans; i < K; ++i) {
  22. father = new int[N + 1];
  23. for (int index = 1; index <= N; ++index) {
  24. father[index] = index;
  25. }
  26. ans = 0;
  27. in.nextToken();
  28. city = (int) in.nval;
  29. for (int[] edge : edges) {
  30. // 合并分支
  31. if ((edge[0] != city) && (edge[1] != city)) {
  32. union(edge[0], edge[1]);
  33. }
  34. }
  35. for (int index = 1; index <= N; ++index) {
  36. if (index == father[index]) {
  37. ++ans;
  38. }
  39. }
  40. // ans为包括city在内的独立连通分支数量
  41. out.println(ans - 2);
  42. }
  43. out.flush();
  44. }
  45. private static int find(int x) {
  46. if (x == father[x]) {
  47. return x;
  48. }
  49. father[x] = find(father[x]);
  50. return father[x];
  51. }
  52. private static void union(int a, int b) {
  53. a = find(a);
  54. b = find(b);
  55. if (a != b) {
  56. father[a] = b;
  57. }
  58. }
  59. }