题意:

求出度为0的强连通分量.

思路:

缩点

具体有两种实现:

1.遍历所有边, 边的两端点不在同一强连通分量的话, 将出发点所在强连通分量出度+1.

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <stack>
  4. #include <algorithm>
  5. using namespace std;
  6. //0.03s 4856K
  7. const int MAXN = 5005;
  8. struct Pool
  9. {
  10. int pre, v;
  11. }p[MAXN*100];//适当开
  12. int num,head[MAXN];
  13. int low[MAXN];
  14. int dfn[MAXN],Index;
  15. int id[MAXN],size;
  16. bool vis[MAXN];
  17. stack<int> s;
  18. int n,m;
  19. int deg[MAXN];
  20.  
  21. void clear()
  22. {
  23. num = 1;//求邻边,异或方便,从2开始
  24. memset(head,0,sizeof(head));
  25. memset(vis,false,sizeof(vis));
  26. memset(low,0,sizeof(low));
  27. memset(dfn,0,sizeof(dfn));
  28. memset(deg,0,sizeof(deg));
  29. Index = size = 0;
  30. while(!s.empty()) s.pop();
  31. }
  32.  
  33. void add(int u, int v)
  34. {
  35. p[++num].v = v;
  36. p[num].pre = head[u];//pre为0,说明该边为第一条边
  37. head[u] = num;
  38. }
  39.  
  40. void Tarjan(int u)
  41. {
  42. dfn[u] = low[u] = ++Index;
  43. s.push(u);
  44. vis[u] = true;
  45. for(int tmp = head[u],k;k = p[tmp].v,tmp; tmp = p[tmp].pre)
  46. {
  47. if(!dfn[k])
  48. {
  49. Tarjan(k);
  50. low[u] = min(low[u], low[k]);
  51. }
  52. else if(vis[k])
  53. {
  54. low[u] = min(low[u], low[k]);
  55. ///low[u] = min(low[u], dfn[k]);这两种都可以啦~
  56. }
  57. }
  58.  
  59. if(dfn[u]==low[u])
  60. {
  61. size++;
  62. int k;
  63. do
  64. {
  65. k = s.top(); s.pop();
  66. vis[k] = false;
  67. id[k] = size;
  68. }while(k!=u);
  69. }
  70. }
  71.  
  72. void cal()
  73. {
  74. for(int i=1;i<=n;i++)
  75. {
  76. for(int tmp = head[i],k;k = p[tmp].v,tmp; tmp = p[tmp].pre)
  77. {
  78. if(id[i]!=id[k])
  79. {
  80. deg[id[i]]++;
  81. }
  82. }
  83. }
  84. }
  85.  
  86. int main()
  87. {
  88. while(scanf("%d",&n),n)
  89. {
  90. clear();
  91. scanf("%d",&m);
  92. for(int i=0,u,v;i<m;i++)
  93. {
  94. scanf("%d %d",&u,&v);
  95. add(u,v);
  96. }
  97. for(int i=1;i<=n;i++)
  98. {
  99. if(!dfn[i])
  100. Tarjan(i);
  101. }
  102. cal();
  103. bool blank = false;
  104. for(int i=1;i<=n;i++)
  105. {
  106. if(!deg[id[i]])
  107. {
  108. if(!blank)
  109. {
  110. printf("%d",i);
  111. blank = true;
  112. }
  113. else
  114. printf(" %d",i);
  115. }
  116. }
  117. printf("\n");
  118. }
  119. }

2. 在dfs的过程中,标记出度.

设当前节点为u

若访问到了黑色点, 则出度不为0.

若访问到了灰色点, 正常

若访问到了白色点, 则这个白色点k

若被搜索之后属于同一强连通分量,则low[ k ] < dfn[ k ] (注意,并不一定有 low[ k ] < low[ u ], 因为k可能连接到了较靠后的灰色点,而u之前已经被较靠前的灰色点更新过).

若被搜索之后属于另一个(不同于u的)强连通分量, 那么可以证明 low[ k ] == dfn[ k ], 即k一定是入口.

黑体字的两条就包括了所有出度非0的情况. 据此来实现缩点.

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <stack>
  4. #include <algorithm>
  5. using namespace std;
  6. //0.03s 4812K
  7. const int MAXN = 5005;
  8. struct Pool
  9. {
  10. int pre, v;
  11. }p[MAXN*100];//适当开
  12. int num,head[MAXN];
  13. int low[MAXN];
  14. int dfn[MAXN],Index;
  15. int id[MAXN],size;
  16. bool vis[MAXN];
  17. stack<int> s;
  18. int n,m;
  19. bool black[MAXN];
  20. bool odd[MAXN];
  21.  
  22. void clear()
  23. {
  24. num = 1;
  25. memset(head,0,sizeof(head));
  26. memset(vis,false,sizeof(vis));
  27. memset(low,0,sizeof(low));
  28. memset(dfn,0,sizeof(dfn));
  29. memset(black,false,sizeof(black));
  30. memset(odd,false,sizeof(odd));
  31. Index = size = 0;
  32. while(!s.empty()) s.pop();
  33. }
  34.  
  35. void add(int u, int v)
  36. {
  37. p[++num].v = v;
  38. p[num].pre = head[u];
  39. head[u] = num;
  40. }
  41.  
  42. void Tarjan(int u)
  43. {
  44. dfn[u] = low[u] = ++Index;
  45. s.push(u);
  46. vis[u] = true;
  47. for(int tmp = head[u],k;k = p[tmp].v,tmp; tmp = p[tmp].pre)
  48. {
  49. if(!dfn[k])
  50. {
  51. Tarjan(k);
  52. if(low[k]==dfn[k])///如果访问到了白色点,那么新的强连通分量的入口一定在这个点
  53. black[u] = true;
  54. low[u] = min(low[u], low[k]);
  55. }
  56. else if(vis[k])
  57. {
  58. low[u] = min(low[u], low[k]);
  59. }
  60. else
  61. black[u] = true;
  62. }///low只是指"当前找到的强连通分量的进入时间戳"
  63. ///而非"极大强连通分量"的进入时间戳.但是肯定小于自己的时间戳(恰好是进入点的话就是等于).
  64. if(dfn[u]==low[u])
  65. {
  66. size++;
  67. int k;
  68. do
  69. {
  70. k = s.top(); s.pop();
  71. vis[k] = false;
  72. id[k] = size;
  73. if(black[k])
  74. odd[size] = true;
  75. }while(k!=u);
  76. }
  77. }
  78.  
  79. int main()
  80. {
  81. while(scanf("%d",&n),n)
  82. {
  83. clear();
  84. scanf("%d",&m);
  85. for(int i=0,u,v;i<m;i++)
  86. {
  87. scanf("%d %d",&u,&v);
  88. add(u,v);
  89. }
  90. for(int i=1;i<=n;i++)
  91. {
  92. if(!dfn[i])
  93. Tarjan(i);
  94. }
  95. bool blank = false;
  96. for(int i=1;i<=n;i++)
  97. {
  98. if(!odd[id[i]])
  99. {
  100. if(!blank)
  101. {
  102. printf("%d",i);
  103. blank = true;
  104. }
  105. else
  106. printf(" %d",i);
  107. }
  108. }
  109. printf("\n");
  110. }
  111. }

[poj 2553]The Bottom of a Graph[Tarjan强连通分量]的更多相关文章

  1. POJ 2553 The Bottom of a Graph(强连通分量)

    POJ 2553 The Bottom of a Graph 题目链接 题意:给定一个有向图,求出度为0的强连通分量 思路:缩点搞就可以 代码: #include <cstdio> #in ...

  2. poj 2553 The Bottom of a Graph【强连通分量求汇点个数】

    The Bottom of a Graph Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 9641   Accepted:  ...

  3. POJ 2553 The Bottom of a Graph(强连通分量的出度)

    题意: 求出图中所有汇点 定义:点v是汇点须满足 --- 对图中任意点u,若v可以到达u则必有u到v的路径:若v不可以到达u,则u到v的路径可有可无. 模板:http://www.cnblogs.co ...

  4. POJ 2553 The Bottom of a Graph (Tarjan)

    The Bottom of a Graph Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 11981   Accepted: ...

  5. POJ 2553 The Bottom of a Graph Tarjan找环缩点(题解解释输入)

    Description We will use the following (standard) definitions from graph theory. Let V be a nonempty ...

  6. POJ 2553 The Bottom of a Graph TarJan算法题解

    本题分两步: 1 使用Tarjan算法求全部最大子强连通图.而且标志出来 2 然后遍历这些节点看是否有出射的边,没有的顶点所在的子强连通图的全部点,都是解集. Tarjan算法就是模板算法了. 这里使 ...

  7. poj 2553 The Bottom of a Graph(强连通、缩点、出入度)

    题意:给出一个有向图G,寻找所有的sink点.“sink”的定义为:{v∈V|∀w∈V:(v→w)⇒(w→v)},对于一个点v,所有能到达的所有节点w,都能够回到v,这样的点v称为sink. 分析:由 ...

  8. poj 2553 The Bottom of a Graph(强连通分量+缩点)

    题目地址:http://poj.org/problem?id=2553 The Bottom of a Graph Time Limit: 3000MS   Memory Limit: 65536K ...

  9. POJ 2553 The Bottom of a Graph 【scc tarjan】

    图论之强连通复习开始- - 题目大意:给你一个有向图,要你求出这样的点集:从这个点出发能到达的点,一定能回到这个点 思路:强连通分量里的显然都可以互相到达 那就一起考虑,缩点后如果一个点有出边,一定不 ...

随机推荐

  1. sql 自身连接

    "select table1.field1, table2.field1 from table table1, table table2 where table1.id=table2.par ...

  2. 『奇葩问题集锦』npm install 报错 node-pre-gyp ERR! node-pre-gyp -v v0.6.25

    gyp ERR! configure error gyp ERR! stack Error: Can't find Python executable "python", you ...

  3. lamp环境-编译安装

    http://my.oschina.net/JerryBaby/blog/292731 http://blog.chinaunix.net/uid-20639775-id-154442.html ht ...

  4. 以中断方式实现1s定时

    中断方式比较特殊,需要使用单片机内部的中断处理机制,同时指定中断函数. #include <reg52.h> sbit LED = P0^; unsigned ; void main() ...

  5. 在同一台机器上让Microsoft SQL Server 2000/ SQL2005/ SQL2008共存

    可能很多朋友都遇到想同时在自己的机器上运行Microsoft SQL Server 2000以及Microsoft SQL Server 2005和Microsoft SQL Server 2008. ...

  6. 跨线程操作UI控件

    写程序的时候经常会遇到跨线程访问控件的问题,看到不少人去设置Control.CheckForIllegalCrossThreadCalls = false;这句话是告诉编译器不要对跨线程访问作检查,可 ...

  7. xcode 自动添加注释,生成文档

    一.自动生成注释代码        添加一个快捷键,生成 注释代码        ThisService 下载连接:http://wafflesoftware.net/thisservice/     ...

  8. XE5 开发android平台搭建

    转载自:http://www.cnblogs.com/hezihang/p/3319980.html Delphi XE5的Android开发平台搭建   Delphi XE5支持Android AR ...

  9. [JavaScript] js实现简单的代码运行框

    <script type="text/javascript">// <![CDATA[ function runCode(obj) { var winname = ...

  10. python中的字典(dict),列表(list),元组(tuple)

    一,List:列表 python内置的一种数据类型是列表:list.list是一种有序的数据集合,可以随意的添加和删除其中的数据.比如列出班里所有的同学的名字,列出所有工厂员工的工号等都是可以用到列表 ...