所以Tarjan到底怎么读

强连通分量

  • 基本概念

    • 强连通 如果两个顶点可以相互通达,则称两个顶点强连通
    • 强连通图 如果有向图G的每两个顶点都强连通,称G是一个强连通图。
  • Tarjan

    Tarjan算法是基于对图深度优先搜索的算法,每个强连通分量为搜索树中的一棵子树。搜索时,把当前搜索树中未处理的节点加入一个堆栈,回溯时可以判断栈顶到栈中的节点是否为一个强连通分量。
  • 定义
    • dfn[u]: 为节点u搜索的次序编号(时间戳)
    • low[u]: 为u或u的子树能够追溯到的最早的栈中节点的次序号。
  • 判定
    • low[u]:=min(low[u],dfn[v])——(u,v)为后向边,v不是u的子树;
    • low[u]:=min(low[u],low[v])——(u,v)为树枝边,v为u的子树;
    • 当DFN(u)=Low(u)时,以u为根的搜索子树上所有节点是一个强连通分量。

模板题:信息传递

题目描述

有n个同学(编号为1到n)正在玩一个信息传递的游戏。在游戏里每人都有一个固定的信息传递对象,其中,编号为i的同学的信息传递对象是编号为Ti同学。

游戏开始时,每人都只知道自己的生日。之后每一轮中,所有人会同时将自己当前所知的生日信息告诉各自的信息传递对象(注意:可能有人可以从若干人那里获取信息,但是每人只会把信息告诉一个人,即自己的信息传递对象)。当有人从别人口中得知自己的生日时,游戏结束。请问该游戏一共可以进行几轮?

输入

输入共2行。

第1行包含1个正整数n表示n个人。 n ≤ 200000

第2行包含n个用空格隔开的正整数T1,T2,……,Tn,其中第i个整数Ti示编号为i的同学的信息传递对象是编号为Ti的同学,Ti≤n且Ti≠i。数据保证游戏一定会结束。

输出

输出共 1 行,包含 1 个整数,表示游戏一共可以进行多少轮。

样例输入

5

2 4 2 3 1

样例输出

3

提示

游戏的流程如图所示。当进行完第 3 轮游戏后,4 号玩家会听到 2 号玩家告诉他自

己的生日,所以答案为 3。当然,第 3 轮游戏后,2 号玩家、3 号玩家都能从自己的消息

来源得知自己的生日,同样符合游戏结束的条件。

  1. #include<bits/stdc++.h>
  2. #define ll long long
  3. #define ull unsigned long long
  4. #define met(a,x) memset(a,x,sizefo(a))
  5. #define inf 0x3f3f3f3f
  6. using namespace std;
  7. const int maxn=2e5+10;
  8. int n,tol,dep;
  9. int head[maxn],low[maxn],dfn[maxn],ans=maxn;
  10. bool vis[maxn];
  11. stack<int>st;
  12. struct edge
  13. {
  14. int v,next;
  15. }e[maxn];
  16. void addedge(int u,int v)
  17. {
  18. e[++tol].next=head[u];
  19. e[tol].v=v;
  20. head[u]=tol;
  21. }
  22. void tarjian(int u)
  23. {
  24. dfn[u]=low[u]=++dep;
  25. st.push(u);
  26. vis[u]=true;
  27. for(int i=head[u];i;i=e[i].next){
  28. int v=e[i].v;
  29. if(!dfn[v]){
  30. tarjian(v);
  31. low[u]=min(low[u],low[v]);
  32. }else if(vis[v]){
  33. low[u]=min(low[u],dfn[v]);
  34. }
  35. }
  36. if(low[u]==dfn[u]){
  37. int cnt=0;
  38. while(1){
  39. int now=st.top();
  40. st.pop();
  41. vis[u]=0;
  42. cnt++;
  43. if(now==u)break;
  44. }
  45. if(cnt>1) ans=min(ans,cnt);
  46. }
  47. }
  48. int main()
  49. {
  50. scanf("%d",&n);
  51. int v;
  52. for(int i=1;i<=n;i++){
  53. scanf("%d",&v);
  54. addedge(i,v);
  55. }
  56. for(int i=1;i<=n;i++){
  57. if(!dfn[i]){
  58. tarjian(i);
  59. }
  60. }
  61. printf("%d\n",ans);
  62. return 0;
  63. }

求割点

  • 基本概念

    • 割点:若删掉某点后,原连通图分裂为多个子图,则称该点为割点。
    • 若low[v]>=dfn[u],则u为割点。因low[v]>=dfn[u],则说明v通过子孙无法到达u的祖先。那么对于原图,去掉u后,必然会分成两个子图。
  • 模板
  1. /*
  2. * 求无向图的割点和桥
  3. * 可以找出割点和桥,求删掉每个点后增加的连通块。
  4. * 需要注意重边的处理,可以先用矩阵存,再转邻接表,或者进行判重
  5. */
  6. const int MAXN = 1e5+10;
  7. const int MAXM = 2e5+10;
  8. struct Edge
  9. {
  10. int to,next;
  11. bool cut;
  12. } edge[MAXM];
  13. int head[MAXN],tot=1;
  14. int Low[MAXN],DFN[MAXN],Stack[MAXN];
  15. int Index,top;
  16. bool Instack[MAXN];
  17. bool cut[MAXN];
  18. int add_block[MAXN];
  19. int bridge;
  20. void addedge(int u,int v)
  21. {
  22. edge[tot].to = v;
  23. edge[tot].next = head[u];
  24. edge[tot].cut = false;
  25. head[u] = tot++;
  26. }
  27. void Tarjan(int u,int pre)
  28. {
  29. int v;
  30. Low[u] = DFN[u] = ++Index;
  31. Stack[top++] = u;
  32. Instack[u] = true;
  33. int son = 0;
  34. int pre_cnt=0;
  35. for(int i=head[u]; i; i=edge[i].next)
  36. {
  37. v = edge[i].to;
  38. if(v == pre && pre_cnt == 0)
  39. {
  40. pre_cnt++;
  41. continue;
  42. }
  43. if(!DFN[v])
  44. {
  45. son++;
  46. Tarjan(v,u);
  47. if(Low[u] > Low[v])
  48. Low[u] = Low[v];
  49. if(Low[v] > DFN[u])//桥
  50. {
  51. bridge++;
  52. edge[i].cut = true;
  53. edge[i^1].cut = true;
  54. }
  55. if(u != pre && Low[v] >= DFN[u])//割点
  56. {
  57. cut[u] = true;
  58. add_block[u]++;
  59. }
  60. }
  61. else if( Low[u] > DFN[v])
  62. Low[u] = DFN[v];
  63. }
  64. if(u == pre && son > 1)//割点
  65. {
  66. cut[u] = true;
  67. }
  68. if(u == pre)
  69. add_block[u] = son - 1;
  70. Instack[u] = false;
  71. top--;
  72. }

求桥

  • 基本概念

    • 桥(割边):删掉它之后,图必然会分裂为两个或两个以上的子图。
    • 原理:若low[v]>dfn[u],则(u,v)为桥。由割点同理可得。但是由于可能存在重边,需要把一条无向边拆成的两条标号相同的有向边,记录每个点的父亲到它的边的标号,如果边(u,v)是v的父亲边,就不能用dfn[u]更新low[v]。这样如果遍历完v的所有子节点后,发现low[v]=dfn[v],说明u的父亲边(u,v)为割边。

点双连通分量

对于点双连通分支,实际上在求割点的过程中就能顺便把每个点双连通分支求出。建立一个

栈,存储当前双连通分支,在搜索图时,每找到一条树枝边或后向边(非横叉边),就把这条

边加入栈中。如果遇到某时满足DFN(u)<=Low(v),说明u 是一个割点,同时把边从栈顶一

个个取出,直到遇到了边(u,v),取出的这些边与其关联的点,组成一个点双连通分支。割点

可以属于多个点双连通分支,其余点和每条边只属于且属于一个点双连通分支。

模板题 Go around the Labyrinth

题目描述

Explorer Taro got a floor plan of a labyrinth. The floor of this labyrinth is in the form of a two-dimensional grid. Each of the cells on the floor plan corresponds to a room and is indicated whether it can be entered or not. The labyrinth has only one entrance located at the northwest corner, which is upper left on the floor plan. There is a treasure chest in each of the rooms at other three corners, southwest, southeast, and northeast. To get a treasure chest, Taro must move onto the room where the treasure chest is placed.

Taro starts from the entrance room and repeats moving to one of the enterable adjacent rooms in the four directions, north, south, east, or west. He wants to collect all the three treasure chests and come back to the entrance room. A bad news for Taro is that, the labyrinth is quite dilapidated and even for its enterable rooms except for the entrance room, floors are so fragile that, once passed over, it will collapse and the room becomes not enterable. Determine whether it is possible to collect all the treasure chests and return to the entrance.

输入

The input consists of at most 100 datasets, each in the following format.

N M

c1,1...c1,M

...

cN,1...cN,M

The first line contains N, which is the number of rooms in the north-south direction, and M, which is the number of rooms in the east-west direction. N and M are integers satisfying 2 ≤ N ≤ 50 and 2 ≤ M ≤ 50. Each of the following N lines contains a string of length M. The j-th character ci,j of the i-th string represents the state of the room (i,j), i-th from the northernmost and j-th from the westernmost; the character is the period ('.') if the room is enterable and the number sign ('#') if the room is not enterable. The entrance is located at (1,1), and the treasure chests are placed at (N,1), (N,M) and (1,M). All of these four rooms are enterable. Taro cannot go outside the given N × M rooms.

The end of the input is indicated by a line containing two zeros.

输出

For each dataset, output YES if it is possible to collect all the treasure chests and return to the entrance room, and otherwise, output NO in a single line.

这题是训练赛的一道,算是裸模板题

左上角的点能到达右上角,右下角,左下角,然后回到原点。这题采用Tarjian求,然后判断四个角属不属于一个双连通分量,然后把割点也标记一下。因为割点属于任何一双连通分量。

  1. #include <bits/stdc++.h>
  2. #define ll long long
  3. using namespace std;
  4. const int maxm=1e5+10;
  5. const int maxn=5e5+10;
  6. struct Edge
  7. {
  8. int v,next;
  9. }e[maxm];
  10. int head[maxn],tol,cur,top,block;
  11. bool instack[maxn];
  12. int low[maxn],dfn[maxn],Stack[maxn],belong[maxn],cnt;
  13. void addedge(int u,int v)
  14. {
  15. e[++tol].v=v;
  16. e[tol].next=head[u];
  17. head[u]=tol;
  18. }
  19. void Tarjian(int u,int pre)
  20. {
  21. int v;
  22. low[u]=dfn[u]=++cur;
  23. Stack[top++]=u;
  24. instack[u]=true;
  25. for(int i=head[u];i;i=e[i].next){
  26. v=e[i].v;
  27. if(v==pre) continue;
  28. if(!dfn[v]){
  29. Tarjian(v,u);
  30. if(low[u]>low[v])
  31. low[u]=low[v];
  32. if(low[v]>=dfn[u]){
  33. block++;
  34. int vn;
  35. do{
  36. vn=Stack[--top];
  37. belong[vn]=block;
  38. instack[vn]=false;
  39. }while(vn!=v);
  40. belong[u]=block;
  41. }
  42. }
  43. else if(instack[v]&&low[u]>dfn[v]){
  44. low[u]=dfn[v];
  45. }
  46. }
  47. }
  48. int num[55][55];
  49. void init()
  50. {
  51. memset(low,0,sizeof(low));
  52. memset(dfn,0,sizeof(dfn));
  53. memset(head,0,sizeof(head));
  54. memset(belong,0,sizeof(belong));
  55. memset(instack,0,sizeof(instack));
  56. memset(num,0,sizeof(num));
  57. tol=top=cur=block=0;
  58. cnt=0;
  59. }
  60. int mapp[55][55];
  61. int main(){
  62. int n,m;
  63. char s;
  64. while(scanf("%d%d",&n,&m)&&n&&m){
  65. init();
  66. for(int i=1;i<=n;i++){
  67. for(int j=1;j<=m;j++){
  68. scanf(" %c",&s);
  69. num[i][j]=++cnt;
  70. if(s=='.'){
  71. mapp[i][j]=1;
  72. }
  73. else{
  74. mapp[i][j]=0;
  75. }
  76. }
  77. }
  78. for(int i=1;i<=n;i++){
  79. for(int j=1;j<=m;j++){
  80. if(num[i-1][j]&&mapp[i-1][j]){
  81. addedge(num[i][j],num[i-1][j]);
  82. }
  83. if(num[i+1][j]&&mapp[i+1][j]){
  84. addedge(num[i][j],num[i+1][j]);
  85. }
  86. if(num[i][j+1]&&mapp[i][j+1]){
  87. addedge(num[i][j],num[i][j+1]);
  88. }
  89. if(num[i][j-1]&&mapp[i][j-1]){
  90. addedge(num[i][j],num[i][j-1]);
  91. }
  92. }
  93. }
  94. for(int i=1;i<=cnt;i++)if(!dfn[i])
  95. Tarjian(i,-1);
  96. int a,b,c,d;
  97. a=belong[num[1][1]];
  98. b=belong[num[1][m]];
  99. c=belong[num[n][1]];
  100. d=belong[num[n][m]];
  101. //cout<<a<<" "<<b<<" "<<c<<" "<<d<<endl;
  102. if(a==b&&b==c&&c==d){
  103. puts("YES");
  104. }
  105. else puts("NO");
  106. }
  107. return 0;
  108. }

[学习笔记]连通分量与Tarjan算法的更多相关文章

  1. 【转】BYV--有向图强连通分量的Tarjan算法

    转自beyond the void 的博客: https://www.byvoid.com/zhs/blog/scc-tarjan 注:红色为标注部分 [有向图强连通分量] 在有向图G中,如果两个顶点 ...

  2. 机器学习实战(Machine Learning in Action)学习笔记————08.使用FPgrowth算法来高效发现频繁项集

    机器学习实战(Machine Learning in Action)学习笔记————08.使用FPgrowth算法来高效发现频繁项集 关键字:FPgrowth.频繁项集.条件FP树.非监督学习作者:米 ...

  3. 机器学习实战(Machine Learning in Action)学习笔记————07.使用Apriori算法进行关联分析

    机器学习实战(Machine Learning in Action)学习笔记————07.使用Apriori算法进行关联分析 关键字:Apriori.关联规则挖掘.频繁项集作者:米仓山下时间:2018 ...

  4. 机器学习实战(Machine Learning in Action)学习笔记————02.k-邻近算法(KNN)

    机器学习实战(Machine Learning in Action)学习笔记————02.k-邻近算法(KNN) 关键字:邻近算法(kNN: k Nearest Neighbors).python.源 ...

  5. [ML学习笔记] 朴素贝叶斯算法(Naive Bayesian)

    [ML学习笔记] 朴素贝叶斯算法(Naive Bayesian) 贝叶斯公式 \[P(A\mid B) = \frac{P(B\mid A)P(A)}{P(B)}\] 我们把P(A)称为"先 ...

  6. Effective STL 学习笔记 31:排序算法

    Effective STL 学习笔记 31:排序算法 */--> div.org-src-container { font-size: 85%; font-family: monospace; ...

  7. HMM模型学习笔记(前向算法实例)

    HMM算法想必大家已经听说了好多次了,完全看公式一头雾水.但是HMM的基本理论其实很简单.因为HMM是马尔科夫链中的一种,只是它的状态不能直接被观察到,但是可以通过观察向量间接的反映出来,即每一个观察 ...

  8. 【视频编解码·学习笔记】8. 熵编码算法:基本算法列举 & 指数哥伦布编码

    一.H.264中的熵编码基本方法: 熵编码具有消除数据之间统计冗余的功能,在编码端作为最后一道工序,将语法元素写入输出码流 熵解码作为解码过程的第一步,将码流解析出语法元素供后续步骤重建图像使用 在H ...

  9. poj1523求割点以及割后连通分量数tarjan算法应用

    无向图,双向通道即可,tarjan算法简单应用.点u是割点,条件1:u是dfs树根,则u至少有2个孩子结点.||条件2:u不是根,dfn[u]=<low[v],v是u的孩子结点,而且每个这样的v ...

随机推荐

  1. DispatcherServlet(2)_HandlerMapping

    HandlerMapping_xmind SpringMVC默认提供的HandlerMapping BeanNameUrlHandlerMapping SimpleUrlHandlerMapping ...

  2. Swift—UITextField的基本用法

    https://www.jianshu.com/p/63bdeca39ddf 1.文本输入框的创建##### let textField = UITextField(frame: CGRect(x:1 ...

  3. Hadoop家族系统学习路线

    本文主要介绍Hadoop家族产品,常用的项目包括Hadoop,Hive,Pig,HBase,Sqoop,Mahout,Zookeeper,Avro,Ambari,Chukwa,新增加的项目包括,YAR ...

  4. 澳洲Essay写作常见误区汇总

    近年来,想要不断提升自己开拓视野选择留学的学生越来越多,留学生们对于澳洲essay的写作并不生疏,可是许多人并不能很好地完成澳洲essay的写作,因为留学生们对于澳洲essay写作并不怎么了解.其实, ...

  5. 高级css效果

    1.图片渐变效果 background linear-gradient(top,rgba(0,0,0,.8),rgba(0,0,0,.8))

  6. javascript语法规范和良好的变成习惯

    1.1空白和多行书写 1.空白:空格键输入的空白.tab键输入的空白以及回车键输入的空白 2.多行书写,不能将引号内的字符串放到两行,不然容易报错. 1.2点语法 . 点语法表达式由对象开始,接着是一 ...

  7. java 微信红包算法代码实现及架构设计

    转载至:https://www.zybuluo.com/yulin718/note/93148 微信红包的架构设计简介 架构 @来源于QCon某高可用架构群整理,整理朱玉华. 背景:有某个朋友在朋友圈 ...

  8. POJ 1080:Human Gene Functions LCS经典DP

    Human Gene Functions Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 18007   Accepted:  ...

  9. org.springframework.test.context.junit4.SpringJUnit4ClassRunner

    项目中有了spring-test的依赖,里面确实也有 org.springframework.test.context.junit4.SpringJUnit4ClassRunner 此类,但是项目就是 ...

  10. Q2:Add Two Numbers

    2. Add Two Numbers 官方的链接:2. Add Two Numbers Description : You are given two non-empty linked lists r ...