• POJ 2186


    题目大意:

    给定一个含N个点、M条边的有向图,求其中有多少个点,可以由其他任意一点出发到达它?

    N<=1e4,M<=5e4。

    为了描述和编程简便,我们建立原图的反图,这样问题转化为:有多少个点满足从它出发可以到达其他任意一点。

    若无特殊说明,以下所指的图均为反图

    引理1:满足条件的所有点必然在同一强连通分量内。

    证明很简单,如果它们不在同一强连通分量内,那么其中必然有两点x,y使得x→y的路径不存在,与题目要求矛盾。

    我们考虑求出该图的所有强连通分量,然后对于每个强连通分量,检验从其中任一点出发,能否到达其他所有的点。

    我们可以采取缩点的方法,将每个强连通分量缩成一个点。

    引理2:缩点后的图必然是一个有向无环图(DAG)。

    证明:如果缩点后存在环,那么这个环可以合并成一个更大的强连通分量。这与强连通分量的极大性矛盾。

    我们统计缩点后每个点的入度。如果有2个或以上的点入度为0,那么它们是互相不可达的,此时答案为0。

    否则,如果只有一个点入度为0,答案就是该点所代表的强连通分量的大小。

    实现时可以借助两个数组:sccId[x]表示点x所属的强连通分量的编号,sccSize[x]表示点x所属的强连通分量的大小。

    参考:有向图强连通分量的Tarjan算法

    代码:

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <algorithm>
      4 #include <stack>
      5 
      6 #define FILLARR(arr, ch) memset(arr, ch, sizeof(arr))
      7 
      8 const int maxN = (int)1e4 + 5;
      9 const int maxM = (int)5e4 + 5;
     10 
     11 struct Edge
     12 {
     13     int to, next;
     14     void assign(int t, int n)
     15     {
     16         to = t;
     17         next = n;
     18     }
     19 };
     20 
     21 Edge elist[maxM];
     22 int head[maxN];
     23 int ecnt;
     24 int N, M;
     25 
     26 void initElist()
     27 {
     28     FILLARR(head, -1);
     29     ecnt = 0;
     30 }
     31 
     32 inline void addEdge(int from, int to)
     33 {
     34     elist[ecnt].assign(to, head[from]);
     35     head[from] = (ecnt++);
     36 }
     37 
     38 void input()
     39 {
     40     scanf("%d%d", &N, &M);
     41     initElist();
     42     for (int u, v, i = 0; i < M; i++)
     43     {
     44         scanf("%d%d", &u, &v);
     45         addEdge(v, u);
     46     }
     47 }
     48 
     49 int dfn[maxN];
     50 int low[maxN];
     51 bool inStk[maxN];
     52 int sccId[maxN];
     53 int sccSize[maxN];
     54 int lastDfn = 0;
     55 std::stack<int> stk;
     56 
     57 inline void pushToStk(int v)
     58 {
     59     stk.push(v);
     60     inStk[v] = true;
     61 }
     62 
     63 inline int popFromStk()
     64 {
     65     int v = stk.top();
     66     stk.pop();
     67     inStk[v] = false;
     68     return v;
     69 }
     70 
     71 void dfs(int cur)
     72 {
     73     dfn[cur] = low[cur] = (++lastDfn);
     74     pushToStk(cur);
     75 
     76     for (int e = head[cur]; e != -1; e = elist[e].next)
     77     {
     78         int to = elist[e].to;
     79         if (dfn[to] == 0)
     80         {
     81             dfs(to);
     82             low[cur] = std::min(low[cur], low[to]);
     83         }
     84         else if (inStk[to])
     85             low[cur] = std::min(low[cur], dfn[to]);
     86     }
     87 
     88     if (dfn[cur] == low[cur])
     89     {
     90         for (int v = popFromStk(); ; v = popFromStk())
     91         {
     92             sccId[v] = cur;
     93             sccSize[cur] += 1;
     94             if (v == cur)
     95                 break;
     96         }
     97     }
     98 }
     99 
    100 int inDeg[maxN]; //compressed graph in which each SCC is compressed into one node
    101 
    102 int solve()
    103 {
    104     for (int i = 1; i <= N; i++)
    105         if (dfn[i] == 0)
    106             dfs(i);
    107 
    108     for (int i = 1; i <= N; i++)
    109         inDeg[i] = (sccId[i] == i ? 0 : -1);
    110 
    111     for (int i = 1; i <= N; i++)
    112         for (int e = head[i]; e != -1; e = elist[e].next)
    113         {
    114             int to = elist[e].to;
    115             if (sccId[i] != sccId[to])
    116                 inDeg[sccId[to]] += 1; //link between two SCCs
    117         }
    118 
    119     int head = (int)(std::find(inDeg + 1, inDeg + N + 1, 0) - inDeg);
    120     return std::count(inDeg + head + 1, inDeg + N + 1, 0) > 0 ? 0 : sccSize[head];
    121 }
    122 
    123 int main()
    124 {
    125     input();
    126     printf("%d", solve());
    127     return 0;
    128 }
  • 相关阅读:
    字体填充
    通过浏览器直接打开Android应用程序
    IE能够打开网页 可是chrome和火狐打不开网页解决的方法
    openGl学习之加入颜色
    站点变为黑白
    POJ 3169 Layout (图论-差分约束)
    自己定义控件-GifView
    标准C函数库的使用方法
    MyEclipse中jsp的凝视报错解决
    Surrounded Regions
  • 原文地址:https://www.cnblogs.com/Onlynagesha/p/8455973.html
Copyright © 2020-2023  润新知