今天终于第一次写了强连通分量的题目

虽然以前老早就知道有这么个东西,对这个东西也有概念,但是确实从来没有写过判别的算法

原来如此简单,但是确实也很巧妙。

在算法导论上面看到的K算法,方法就是做两遍DFS,因为强连通分量有一个性质,就是如果把所有的边反向,那么它仍然是一个强连通分量。

但是今天我用的是Tarjan算法,据说效率比K算法高很多,事实上也应该是这样,因为Tarjan算法只做了一次DFS

其实思想也很简单,就是一直DFS(u),向下向下向下,如果突然发现有一个点可以回到u了,那么这个肯定是一个强连通分量。

哈哈,是不是很通俗。

严格的定义过程大家可以看这里http://www.cmykrgb123.cn/blog/scc-tarjan/

我也是参考了这个才做出来的Tarjan算法,Wiki上的那个过于庞大了,虽然封装的非常好

说说本题,其实就是找强连通分量,然后把每个强连通分量当成一个“超点”来考虑

如果这个“超点”的入度为零,那么它就必然是一个源头,统计这样的“超点”的个数,就是第一问的答案。

第二问,如果有一个“超点”入度不是0,但是出度是0,那就说明这个“超点”可以给其他“超点”作贡献。

我们就找这样的点对,把入度是0和出度是0的点连起来。

这样匹配过后,剩下的要么全是入度是0的,要么全是出度是0的,这些就没办法了,随便从一个连通分量连接过来一条边就可以了。

所以第二问的答案就是所有的“超点”中,入度是0和出度是0的点大的那个数。

  1 import java.io.*;
  2 import java.util.*;
  3 /*
  4 ID: yanglei4
  5 LANG: JAVA
  6 TASK:schlnet
  7 */
  8 public class schlnet {
  9     boolean[] inStack;
 10     int[] DFN;
 11     int[] LOW;
 12     int index = 0;
 13     int[] Stack;
 14     int top = 0;
 15     int[][] map;
 16     int BelongCount = 0;
 17     int[] belong;
 18     
 19     public void Tarjan(int i) {
 20         DFN[i] = LOW[i] = ++index;
 21         inStack[i] = true;
 22         Stack[top++= i;
 23         for (int j = 1; j <= map[i][0]; j++) {
 24             if (DFN[map[i][j]] == 0) {
 25                 Tarjan(map[i][j]);
 26                 if (LOW[map[i][j]] < LOW[i])
 27                     LOW[i] = LOW[map[i][j]];
 28             }
 29             else if (inStack[map[i][j]] && DFN[map[i][j]] < LOW[i])
 30                 LOW[i] = DFN[map[i][j]];
 31         }
 32         if (DFN[i] == LOW[i]) {
 33             int j = 0;
 34             do {
 35                 j = Stack[--top];
 36                 inStack[j] = false;
 37                 belong[j] = BelongCount;
 38             } while (j != i);
 39             BelongCount++;
 40         }
 41         
 42     }
 43     
 44     public void done() throws IOException {
 45         BufferedReader f = new BufferedReader(new FileReader("schlnet.in"));
 46         PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("schlnet.out")));
 47         int N = Integer.parseInt(f.readLine());
 48         map = new int[N + 1][N + 1];
 49         DFN = new int[N + 1];
 50         LOW = new int[N + 1];
 51         inStack = new boolean[N + 1];
 52         Stack = new int[N + 1];
 53         belong = new int[N + 1];
 54         
 55         Arrays.fill(belong,-1);
 56         for (int i = 1; i <= N; i++) {
 57             StringTokenizer st = new StringTokenizer(f.readLine());
 58             int len = st.countTokens();
 59             map[i][0= len - 1;
 60             for (int j = 1; j <= len - 1; j++)
 61                 map[i][j] = Integer.parseInt(st.nextToken());    
 62         }
 63         
 64         for (int i = 1; i <= N; i++) {
 65             if (DFN[i] == 0)
 66                 Tarjan(i);
 67         }    
 68         boolean[][] dis = new boolean[BelongCount + 1][BelongCount + 1];
 69         for (int i = 1;i <= N;i++) {
 70             for (int k = 1;k <= map[i][0];k++)
 71                 dis[belong[i] + 1][belong[map[i][k]] + 1= true;
 72         }
 73         int[] oud = new int[BelongCount + 1];
 74         int[] ind = new int[BelongCount + 1];
 75         
 76         for (int i = 1;i <= BelongCount;i++) {
 77             for (int j = 1; j<= BelongCount;j++) {
 78                 if (i!=&& dis[i][j]) {
 79                     oud[i]++;
 80                     ind[j]++;
 81                 }
 82             }
 83         }
 84         
 85         int i0 = 0;
 86         int o0 = 0;
 87         for (int i = 1;i <= BelongCount;i++) {
 88             if (ind[i] == 0)
 89                 i0++;
 90             if (oud[i] == 0)
 91                 o0++;
 92         }
 93         
 94         if (BelongCount == 1) {
 95             out.println("1");
 96             out.println("0");
 97         }
 98         else {
 99             out.println(i0);
100             out.println(i0>o0?i0:o0);
101         }    
102         out.close();    
103     }
104 
105     public static void main(String[] args) throws IOException {
106         schlnet t = new schlnet();
107         t.done();
108         System.exit(0);
109     }
110 }
111