• [强联通分量] COJ 1128 Download Station


    两边DFS求强联通分支,缩点;

    算法流程:

    dfs(G);

    dfs(G') in the order which f[] decreases.

      output tree in the dfs forest as a strongly connected component

    第一遍DFS为每个顶点打上时间戳,第二遍是反向DFS,按照时间戳递减的顺序访问每个结点,原图中的边作为反向边进行遍历,此时对于强联通分量必定是可以通过其中任一个点访问到,而原图中时间戳较晚(较早访问到的,注意加时间戳的位置)但不属于某个强联通分量的顶点必然到某个强联通分量有一条单向边,反向DFS时由于原边方向改变,无法通过这条边访问到,而时间戳相对较早的,由于按照时间戳递减顺序遍历在访问到它时,此时可以访问到的强联通分量已经访问过了;

    缩点的方式:缩点在这里只是个概念,对每个顶点记录下属于那个强联通分量,可以通过两层循环对原图中每对顶点,如果不属于同一个联通支且有一条有向边,说明如果真的缩点之后有一条有向边,注意在两个联通支之间添加多条有向边并不能改变入度和出度为0的联通支的个数。

    5WA,反向DFS中的j写做i了,样例竟然通过了,多测试还是有效的。

     1 # include <cstdio>
     2 # include <cstring>
     3 
     4 # define N 100 + 5
     5 
     6 int n;
     7 char g[N][N], vis[N];
     8 int ts, cols;
     9 int f[N], c[N], in[N], out[N];
    10 
    11 int dfs(int i)
    12 {
    13     vis[i] = 1;
    14     for (int j = 1; j <= n; ++j) if (!vis[j] && g[i][j])
    15     {
    16         dfs(j);
    17     }
    18     f[++ts] = i;        // 时间戳
    19 }
    20 
    21 int rdfs(int i)
    22 {
    23     vis[i] = 1;
    24     c[i] = cols;
    25     for (int j = 1; j <= n; ++j) if (!vis[j] && g[j][i])
    26     {
    27         rdfs(j);
    28     }
    29 }
    30 
    31 void solve(void)
    32 {
    33 //    memset(f+1, 0, sizeof(int)*n);
    34     memset(vis+1, 0, sizeof(char)*n);
    35     ts = 0;
    36     for (int i = 1; i <= n; ++i) if (!vis[i])
    37     {
    38         dfs(i);
    39      }
    40      memset(c+1, 0, sizeof(int)*n);
    41     memset(vis+1, 0, sizeof(char)*n);
    42        cols = 0;
    43 
    44 //       for (int i = n; i >= 1; --i) printf("%d\t", f[i]);
    45 //       putchar('\n');
    46 
    47     for (int i = n; i >= 1; --i) if (!vis[f[i]])
    48        {
    49            ++cols;
    50            rdfs(f[i]);
    51     }
    52 
    53     if (cols == 1) {printf("0\n"); return ;}
    54     memset(out+1, 0, sizeof(int)*cols);
    55     memset(in+1, 0, sizeof(int)*cols);
    56     for (int i = 1; i <= n; ++i)
    57     for (int j = 1; j <= n; ++j)
    58     {
    59         if (g[i][j] && (c[i]^c[j]))
    60         {
    61             ++out[c[i]];
    62             ++in[c[j]];
    63           }
    64     }
    65     int x = 0, y = 0;
    66      for (int i = 1; i <= cols; ++i)
    67      {
    68          if (in[i] == 0) ++x;
    69          if (out[i] == 0) ++y;
    70     }
    71     printf("%d\n", x>y ? x:y);
    72 }
    73 
    74 void read_graph(void)
    75 {
    76     for (int i = 1; i <= n; ++i)
    77     {
    78         memset(g[i]+1, 0, sizeof(char)*n);
    79         int x;
    80         while (scanf("%d", &x), x)
    81             g[i][x] = 1;
    82     }
    83 }
    84 
    85 int main()
    86 {
    87     while (~scanf("%d", &n))
    88     {
    89         read_graph();
    90         solve();
    91      }
    92 
    93     return 0;
    94 }

    第一道强联通分支。

  • 相关阅读:
    HTML5/CSS3速成教程
    ECMAScript5.1
    HTML5新特性有哪些,你都知道吗
    如何写出兼容性很好的页面
    数据库三个范式详解
    UML入门
    前端总结·基础篇·CSS(一)布局
    常用的14种HTTP状态码速查手册
    传输层协议TCP和UDP
    js获取地址栏参数
  • 原文地址:https://www.cnblogs.com/JMDWQ/p/2625866.html
Copyright © 2020-2023  润新知