关于tarjan,在下觉得这个算法从本质上是一种暴力求强连通分量的方法,但事实上这也是最有效的求强连通分量的方法之一,它对于处理各种强连通分量中奇怪问题,都可以直接转化,所以比较通用和常见。

  什么是tarjan

  粗略的描述一下(详细描述在百度里很详细)

  首先每个点都有时间戳和最小子树戳。

  时间戳的定义是这个点进行递归的时间,每新递归一次就增加,所以每个点的时间戳都不一样,最小子树戳的定义是当前点的子树上节点中(包括它自己)时间戳的最小值。

  它的基本方法是先把任意一个没有tarjan过的点加入栈,然后把新加入的点当做一棵树的根做处理,先把自己的时间戳和最小子树戳设为自己,然后每次去找根的所链的每条边,如果当前边所接的目标节点没有进行过tarjan,那就再tarjan递归处理,处理后,对比当前点最小子树戳和所搜目标节点的最小子树戳,取最小值;如果已经进行过tarjan,但是当前所搜到的目标节点不在栈里(也就是非当前点的来源节点),那么就什么也不做(因为只要这点进过tarjan就说明一定已经把它所处的强连通分量找过,并且找全,但你当前所处理的点是没进过tarjan的,所以一定不和这种进过栈但当前不在栈的点属于一个强连通分量);最后一种情况进行过tarjan并且当前点再栈里,那么我们只需要对比当前点的最小子树戳和目标节点的时间戳,取最小值。

  如果搜索子树的工作结束了,那么要判断是否当前递归节点的时间戳和最小子树戳相同:如果相同,那么从这个节点一直到栈顶都属于同一个强连通分量,全部弹出;如果不同,结束当前递归。

先贴出tarjan的模板

 1 void tarjan(int sb)
 2 {
 3     low[sb]=time[sb]=++T;
 4     f[sb]=true;
 5     stack[++ass]=sb;
 6     for(int k=head[sb];k!=0;k=e[k].next)
 7     {
 8         if(!time[e[k].aim])
 9         {
10             tarjan(e[k].aim);
11             low[sb]=min(low[sb],low[e[k].aim]);
12         }
13         else if(f[e[k].aim])low[sb]=min(low[sb],time[e[k].aim]);
14     }
15     if(time[sb]==low[sb])
16     {
17         f[sb]=false;
18         while(stack[ass]!=sb)
19             f[stack[ass--]]=false;
20         ass--;
21     }
22 }

在此提供一道tarjan裸题

  codevs1332

  在幻想乡,上白泽慧音是以知识渊博闻名的老师。春雪异变导致人间之里的很多道路都被大雪堵塞,使有的学生不能顺利地到达慧音所在的村庄。因此慧音决定换一个能够聚集最多人数的村庄作为新的教学地点。人间之里由N个村庄(编号为1..N)和M条道路组成,道路分为两种一种为单向通行的,一种为双向通行的,分别用1和2来标记。如果存在由村庄A到达村庄B的通路,那么我们认为可以从村庄A到达村庄B,记为(A,B)。当(A,B)和(B,A)同时满足时,我们认为A,B是绝对连通的,记为<A,B>。绝对连通区域是指一个村庄的集合,在这个集合中任意两个村庄X,Y都满足<X,Y>。现在你的任务是,找出最大的绝对连通区域,并将这个绝对连通区域的村庄按编号依次输出。若存在两个最大的,输出字典序最小的,比如当存在1,3,4和2,5,6这两个最大连通区域时,输出的是1,3,4。

输入描述 Input Description

第1行:两个正整数N,M

第2..M+1行:每行三个正整数a,b,t, t = 1表示存在从村庄a到b的单向道路,t = 2表示村庄a,b之间存在双向通行的道路。保证每条道路只出现一次。

输出描述 Output Description

第1行: 1个整数,表示最大的绝对连通区域包含的村庄个数。

第2行:若干个整数,依次输出最大的绝对连通区域所包含的村庄编号。

下面贴出手写代码

 1 #include<cstdio>
 2 struct shit{
 3     int aim;
 4     int next;
 5     bool use;
 6 }e[50100];
 7 int max(int x,int y)
 8 {
 9     return x>y?x:y;
10 }
11 int min(int x,int y)
12 {
13     return x<y?x:y;
14 }
15 int point,head[5100],n,m,ass,cnt,stack[51000],low[51000],time[51000],ans[51000],a,b,num,T,cl2[51000],cl[10];
16 bool f[51000];
17 void fuck(int x,int y)
18 {
19     e[++point].aim=y;
20     e[point].next=head[x];
21     head[x]=point;
22 }
23 void tarjan(int sb)
24 {
25     int x=ass;
26     stack[++ass]=sb;
27     f[sb]=true;
28     low[sb]=time[sb]=++T;
29     for(int k=head[sb];k!=0;k=e[k].next)
30     {
31         int c=e[k].aim;
32         if(!time[c])
33         {
34             tarjan(c);
35             low[sb]=min(low[sb],low[c]);
36         }
37         else if(f[c])low[sb]=min(low[sb],time[c]);
38     }
39     if(low[sb]==time[sb])
40     {
41         cnt++;
42         if(ass-x>=cl[0])
43         {
44             cl[0]=ass-x;
45             cl[1]=cnt;
46         }
47         for(int i=1;i<=ass-x;i++)
48         {
49             cl2[stack[x+i]]=cnt;
50                 f[stack[x+i]]=false;
51         }
52         ass=x;
53     }
54     return;
55 }
56 int main()
57 {
58     scanf("%d%d",&n,&m);
59     for(int i=1;i<=m;i++)
60     {
61         scanf("%d%d%d",&a,&b,&num);
62         if(num-1)fuck(b,a);
63          fuck(a,b);
64     }
65     for(int i=1;i<=n;i++)
66         if(!time[i])tarjan(i);
67     printf("%d\n",cl[0]);
68     point=0;
69     for(int i=1;i<=n;i++)
70     {
71         if(cl2[i]==cl[1])ans[++point]=i;
72     }
73     for(int i=1;i<=cl[0];i++)
74     {
75         printf("%d ",ans[i]);
76     }
77     return 0;
78 }

View Code

 

转载于:https://www.cnblogs.com/PencilWang/p/5868023.html

图论算法》关于tarjan算法两三事相关推荐

  1. 强连通基础与例题(Kosaraju算法与Tarjan算法)

    目录 Kosaraju算法 Tarjan算法 例题 A:HDU-1269 迷宫城堡 B:HDU-2767 Proving Equivalences C:HDU-1827 Summer Holiday ...

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

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

  3. 有向图强连通分量的Tarjan算法

    有向图强连通分量] 在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly connected).如果有向图G的每两个顶点都强连通,称G是一个强连通图.非强连通图有向图的极大 ...

  4. Tarjan算法及其引申

    位于NOI考纲提高组的[7]级算法 [7]求强联通分量算法 [7]强连通分量的缩点算法 [7]求割点.割边算法 认识Tarjan算法 一种由Robert Tarjan提出的求解有向图强连通分量的线性时 ...

  5. Tarjan算法学习笔记

    一种由Robert Tarjan提出的求解有向图强连通分量的线性时间的算法. [有向图强连通分量] 在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly connected ...

  6. Tarjan算法_LCA

    参考资料:Tarjan算法_LCA  tarjan算法求LCA  Tarjan 算法&模板 只是对其中的代码进行一下注释,如有错误还得回来再改. //不怕别人比你聪明,就怕别人比你聪明还比你努 ...

  7. tarjan算法_【朝夕的ACM笔记】树上问题-最近公共祖先-倍增算法

    [朝夕的ACM笔记]目录与索引 最近公共祖先-倍增算法 一.基本概念 最近公共祖先问题:对于给定的一颗有根树,求其两个节点的最近公共祖先. 祖先:节点本身.节点的父亲.节点父亲的父亲--都是该节点的祖 ...

  8. 有向图强连通分量tarjan算法

    转自:http://www.byvoid.com/blog/scc-tarjan/ http://blog.csdn.net/geniusluzh/article/details/6601514 在有 ...

  9. 洛谷 P3388 【模板】割点(割顶) 根+非根+dfn[]+low[]+不一样的Tarjan算法

    洛谷  P3388 [模板]割点(割顶)  根+非根+dfn[]+low[]+不一样的Tarjan算法 Tarjan算法,详见https://blog.csdn.net/mrcrack/article ...

  10. nyist120 校园网络 (Tarjan算法 / 强连通分量)

    校园网络(nyist 120) 解题思路请看代码块中的注释~ import java.util.Scanner; import java.util.Stack; import java.util.Ve ...

最新文章

  1. 【机器学习】RNN循环神经网络
  2. SpringCloud配置中心-Config
  3. Duktape 集成
  4. [转] C#异步操作
  5. 数学里最令人着迷的公式之一--欧拉公式!
  6. 小程序获取用户地址信息api
  7. 老男孩Linux性能优化实战课程教学
  8. oracle客户端sqlplus安装
  9. 小学计算机网络教室管理制度,计算机网络教室使用管理制度[大全五篇]
  10. C51单片机控制蜂鸣器
  11. 外汇EA之马丁格尔EA
  12. python 操作excel 的包 函数
  13. qlv转mp4失败 解决方法
  14. Android仿京东、天猫商品详情页
  15. Apache Kafka的流式SQL引擎——KSQL
  16. 为什么开源堡垒机不可取
  17. boostrap插件
  18. codeforces 1706.D1 Chopping Carrots (Easy Version)
  19. 基于stm32物联网开发板(2)--LCD屏幕
  20. flutter : Failed to find assets path for “Frameworks/App.framework/flutter_assets“

热门文章

  1. nl.basjes.parse.useragent.UserAgentAnalyzer内存泄漏问题解决
  2. Scala类构造方法的参数可以作为属性来使用
  3. Vuex与登录状态保存
  4. Vue+Spring boot前后端响应流程总结
  5. Mysql order by与limit混用陷阱
  6. linux sd卡 自动挂载 mdev,mdev实现U盘和SD卡的自动挂载
  7. 【简单易懂】c++中组合与聚合
  8. BigInteger用法-Java大数据存储、运算
  9. 最优化——线性规划总结2(单纯形法问题总结,检验数为0和退化)
  10. AQS(CountdownLatch、CyclicBarrier、Semaphore)、FutureTask、BlockingQueue、ForkJoin