校园网络问题

x33g5p2x  于2022-07-04 转载在 其他  
字(2.3k)|赞(0)|评价(0)|浏览(365)

一 原问题链接

Network of Schools - POJ 1236 - Virtual Judge

https://vjudge.net/problem/POJ-1236

二 输出和输出

1 输入

第1行包含1个整数N,表示网络中学校数。学校由前 N 个正整数标识。接下来的 N 行,每一行都描述了接受者列表,第 i+1 行包含学校 i 的接收者的标识符。每个列表都以0结尾。空列表再行中仅包含0。

2 输出

输出包含两行。第1行应包含子任务1的解,第2行应包含子任务2的解。

三 输入和输出样例

1 输入样例

5

2 4 3 0

4 5 0

0

0

1 0

2 输出样例

1

2

四 思路

1 子任务1

至少发送给多少个学校,才能让软件到达所有的学校呢?实际上,求强连通分量并缩点后,每个入度为0的强连通分量都必须收到一个新的软件副本。

输入样例1,构成的图如下所示,其中包含3个强连通分量,缩点后入度为0的强连通分量有1个,至少发送给1个学校即可,即1、2、5 中的任意一个学校。

2 子任务2

至少添加多少个接收关系,才能实现发送给任意一个学校,所有学校都能收到?也就是说,每个强连通分量都必须有入度,又有出度。对入度为0的强连通分量,,至少添加一个入度;对于出度为0的强连通分量,至少添加一个出度。添加的边数为 max(p,q),如下图所示。

特殊情况:若只有一个强连通分量,则至少分发给1个学校,需要添加的边数为0。

五 算法设计

1 采用 Targan 算法求解强连通分量,标记连通分量号。

2 检查每个节点 u 的每个邻接点 v,若连通分量号不同,则 u 连通分量号出度为1,v 连通分量号入度为1。

3 统计入度为0的连通分量数p及出度为0的连通分量q,求 max(p,q)。

六 代码

  1. package graph.poj1236;
  2. import java.util.Scanner;
  3. import java.util.Stack;
  4. public class POJ1236 {
  5. static final int maxn = 1000 + 5;
  6. static int n;
  7. static int head[];
  8. static int belong[];
  9. static int cnt;
  10. static int low[];
  11. static int dfn[];
  12. static int out[]; // 节点的出度
  13. static int in[]; // 节点的入度
  14. static int num;
  15. static int id;
  16. static boolean ins[];
  17. static Stack<Integer> s = new Stack<>();
  18. static Edge e[] = new Edge[maxn << 1];
  19. static {
  20. for (int i = 0; i < e.length; i++) {
  21. e[i] = new Edge();
  22. }
  23. }
  24. static void add(int u, int v) { // 添加一条边u--v
  25. e[++cnt].to = v;
  26. e[cnt].next = head[u];
  27. head[u] = cnt;
  28. }
  29. /**
  30. * 功能描述:tarjan 算法
  31. *
  32. * @param u 起始节点
  33. * @author cakin
  34. * @date 2022/7/3
  35. */
  36. static void tarjan(int u) { // 求解有向图强连通分量
  37. low[u] = dfn[u] = ++num;
  38. ins[u] = true;
  39. s.push(u);
  40. for (int i = head[u]; i != 0; i = e[i].next) {
  41. int v = e[i].to;
  42. if (dfn[v] == 0) {
  43. tarjan(v);
  44. low[u] = Math.min(low[u], low[v]);
  45. } else if (ins[v])
  46. low[u] = Math.min(low[u], dfn[v]);
  47. }
  48. if (low[u] == dfn[u]) {
  49. int v;
  50. id++;
  51. do {
  52. v = s.peek();
  53. s.pop();
  54. belong[v] = id;
  55. ins[v] = false;
  56. } while (v != u);
  57. }
  58. }
  59. static void init() {
  60. head = new int[maxn];
  61. low = new int[maxn];
  62. dfn = new int[maxn];
  63. out = new int[maxn];
  64. in = new int[maxn];
  65. belong = new int[maxn];
  66. ins = new boolean[maxn];
  67. cnt = num = 0;
  68. }
  69. public static void main(String[] args) {
  70. Scanner scanner = new Scanner(System.in);
  71. n = scanner.nextInt();
  72. init();
  73. for (int i = 1; i <= n; i++) {
  74. int v;
  75. while (true) {
  76. v = scanner.nextInt();
  77. if (v == 0) {
  78. break;
  79. }
  80. add(i, v);
  81. }
  82. }
  83. for (int i = 1; i <= n; i++)
  84. if (dfn[i] == 0)
  85. tarjan(i);
  86. for (int u = 1; u <= n; u++)
  87. for (int i = head[u]; i != 0; i = e[i].next) {
  88. int v = e[i].to;
  89. if (belong[u] != belong[v]) {
  90. in[belong[v]]++;
  91. out[belong[u]]++;
  92. }
  93. }
  94. if (id == 1) {
  95. System.out.println(1);
  96. System.out.println(0);
  97. return;
  98. }
  99. int ans1 = 0, ans2 = 0;
  100. for (int i = 1; i <= id; i++) {
  101. if (in[i] == 0)
  102. ans1++;
  103. if (out[i] == 0)
  104. ans2++;
  105. }
  106. System.out.println(ans1);
  107. System.out.println(Math.max(ans1, ans2));
  108. }
  109. }
  110. class Edge {
  111. int to;
  112. int next;
  113. }

七 测试

绿色为输出,白色为输出。

相关文章