Tarjan算法,是以一位计算机界大佬的名字命名的算法,多用于解决LCA,割点,强连通分量等问题,下面是其发明者的简短介绍。

Robert Tarjan,计算机科学家,以LCA、强连通分量等算法闻名。他拥有丰富的商业工作经验,1985年开始任教于普林斯顿大学。

切入正题,我们先来看一下tarjan算法的第一个主要用途:求强连通分量。

1.强连通分量

什么是强连通分量呢?

有向图强连通分量:在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通(strongly connected)。如果有向图G的每两个顶点都强连通,称G是一个强连通图。有向图的极大强连通子图,称为强连通分量(strongly connected components)。

通俗一点来说,就是假设有A,B,C三个点,他们之间存在一些线路,使得两两之间直接或间接连接,若在图中属于最多点间的强连通系统,那么这样的一个整体称之为强连通分量。

我们来看一下这个算法的思路:

  1. 定义三个必需的数组和一个必需的全局变量:作为“时间戳”的sequence[amount]数组,记录当前点可以回溯到达的最靠向根节点的一个点的数组lowest_reach[amount],和记录当前点是否在栈中的vis[amount]数组,以及记录当前点的current_turn。如不用STL的话,还可以定义一个模拟栈stacks[amount],和与之配套的指针top,最好由邻接表(链式前向星)存储图。
  2. 从给定的根节点出发,一个枝一个枝地搜索这个数据树,用vis[current_turn]=1标记在栈中的数据, 并以当前点为起点,沿着邻接表已经记录好的路线一直搜寻,若下一个点没有被访问,则直接递归进行更深层的搜索,不然直接将当前点的lowest_reach和这条路下一个点的lowest_reach取最小值。
  3. 驱逐在栈中的且已被判定的强连通分量。

实现代码:

int current_turn=0,top=0;
int secquence[360],stacks[360],lowest_reach[360];
bool vis[360];
///necessary preparation for tarjan
struct node
{int next,to
}nodes[360];
int heads[360];
void tarjan(int current)
{secquence[current]=lowest_reach[current]=++current_turn;stacks[top++]=current;vis[current]=1;for(int heads[current];i!=-1;i=nodes[i].next){int toward=nodes[i].to;if(secquence[towrad]==0){tarjan(toward);lowest_reach[current]=min(lowest_reach[current],lowest_reach[toward]);}else lowest_reach[current]=min(lowest_reach[current],lowest_reach[toward]);
///the other opinion says it should be secquence[toward]if(secquence[current]==lowest_reach[current]){vis[current]=false;while(stacks[top--]!=current){vis[stacks[top--]]=false; } top--;} 

2.割点

看一下割点的定义。

在一个无向图中,如果有一个顶点集合,删除这个顶点集合以及这个集合中所有顶点相关联的边以后,图的连通分量增多,就称这个点集为割点集合。

如果某个割点集合只含有一个顶点X(也即{X}是一个割点集合),那么X称为一个割点。

连通分量指的是若干点间各自互相有直接或者间接联系的系统,这里所说的“增多”可以说是把原图一分为多。也就是说,割点就是,这个点的存在维系着两侧图是否可以连通。

那么我们如何求出这些割点呢?仍然是tarjan算法,但是和上边相比有一些改动。

我们看一下改动后的思路:

  1. 仍然是用sequence数组记录访问次序,lowest_reach记录可以回溯到的最靠近根节点的点,这里的vis数组将直接标记割点,整个过程不需要栈,但需要一个根节点号,和一个用来记录根节点子树的变量child。
  2. 按着邻接表所存储的路线向深处搜索。当我们搜索完下一个结点时,发现访问次序sequence小于等于下一个点的lowest_reach,若等于,则意味着下一个点至少不能回到当前点,也就是说不连通,标记当前点。同时若current_turn回到了根节点,那说明某个线路与根节点是连通的。此时child++,若根节点有两棵及以上的子树,则可以判定这个根节点也是割点。

实现代码:

int current_turn=0,child=0;
int secquence[360],lowest_reach[360];
bool vis[360];
struct node
{int next,to
}nodes[360];
int heads[360];
void tarjan(int current,int root)
{secquence[current]=lowest_reach[current]=++current_turn;child=0;for(int heads[current];i!=-1;i=nodes[i].next){int toward=nodes[i].to;if(secquence[towrad]==0){tarjan(toward);lowest_reach[current]=min(lowest_reach[current],lowest_reach[toward]);if(lowest_reach[current]>=sequence[current]&&current!=rootvis[current]=1;if(current==root)child++;}else lowest_reach[current]=min(lowest_reach[current],lowest_reach[toward]);}if(child>=2&&current==root)vis[current]=1; }

Tarjan算法(求强连通分量与割点)相关推荐

  1. 算法提高课-图论-有向图的强连通分量-AcWing 1174. 受欢迎的牛:tarjan算法求强连通分量、tarjan算法板子、强连通图

    文章目录 题目解答 题目来源 题目解答 来源:acwing 分析: 强连通图:给定一张有向图.若对于图中任意两个结点x,y,既存在从x到y的路径,也存在从y到x的路径,则称该有向图是"强连通 ...

  2. tarjan算法(强连通分量与割点)

    tarjan算法可以求有向图的割点割边强连通分量(还有一些奇奇怪怪的操作) 我只会割点和强连通分量,割边(和缩点)以后可能会加,如果是来看割边的话,现在跑还来得及.. (先来一张有向图叭) 用这张图, ...

  3. POJ2186——并查集+Tarjan算法求强连通分量

    算法讨论:这题陷阱比较多.首先,被所有牛欢迎,这说明所有的牛都要在一个连通图中,也就是将所给的边看成无向边的时候,所有点要在一个连通图中.这个我们用并查集来实现就可以了.强连通分量的求法就很简单了,正 ...

  4. tarjan算法求解强连通分量问题

    Part1:有向图的强连通分量: 一个连通图只有一个联通分量就是自身,非连通图有多个连通分量. 在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从v ...

  5. tarjan算法总结 (强连通分量+缩点+割点),看这一篇就够了~

    文章目录 一.tarjan求强连通分量 1:算法流程 2:模板 二.tarjan缩点 1:相关定义 2:算法流程 三.tarjan求割点.桥 1.什么是割点 2.割点怎么求? 3.割点tarjan模板 ...

  6. 迷宫城堡 HDU - 1269 (塔尖算法求强连通分量)

    为了训练小希的方向感,Gardon建立了一座大城堡,里面有N个房间(N<=10000)和M条通道(M<=100000),每个通道都是单向的,就是说若称某通道连通了A房间和B房间,只说明可以 ...

  7. 超详细Tarjan算法总结,求强连通分量,割点,割边,有重边的割边

    Tarjan是一个人,他一身中发明了很多算法,就这几个算法最为出名. 1.求有向图的强连通分量,那么什么是强连通分量呢,就是一个顶点集合,任意两个顶点间都可以互相到达.一个顶点也是强联通分量如果图中任 ...

  8. 解题报告:luogu P2341 受欢迎的牛(Tarjan算法,强连通分量判定,缩点,模板)

    题目链接:洛谷 受欢迎的牛 基本上算是一道模板题 根据题意,如果有环,意味着这个环里的牛都互相喜欢 我们可以先求出环,然后把每一个环都看作一个点,这样整个图就变成了一个DAG(有向无环图) 看有几个点 ...

  9. Kosaraju算法求强连通分量

    Kosaraju算法 该算法旨在得到深度优先后续排列后的递归探索中,每次调用DFS的所有顶点都属于同一强联通分量.所以可以这么理解:当递归进入一个强联通分量时,把他锁死在这个强联通分量中(即不能从该强 ...

最新文章

  1. 专家解释即将到来的BCH网络升级
  2. C语言 遍历字符串数组
  3. Apache Kafka-初体验Kafka(02)-Centos7下搭建单节点kafka_配置参数详解_基本命令实操
  4. 部署eureka和config
  5. 你是信用卡卡奴吗?怎么摆脱卡奴?
  6. Java“地铁”表(JavaFX)
  7. 优秀程序员必备的15大技能
  8. Spring Boot 2.2 正式发布,大幅性能提升 Java 13 支持 | CSDN 博文精选
  9. [译] 在Web API 2 中实现带JSON的Patch请求
  10. JavaWeb实现简易新闻管理系统
  11. IMX8MM IMX8QXP芯片配置GPIO方向和数据
  12. Structs2 总结
  13. 金山Andorid面试总结
  14. python开新窗口的方法_python tkinter点击按钮打开新窗口
  15. oracle 00002,imp-00002错误
  16. 下载了突袭:资源战争
  17. CRF原理介绍(以BILSTM-CRF模型为例)
  18. 工作流(Workflow) -- 实现简单工作流程
  19. 树莓派 linux 私有云,树莓派搭建私有云服务器
  20. 【ASP.Net】上传图片+水印

热门文章

  1. Lenovo联想笔记本电脑小新Pro-16ACH 2021款(82L5)原装出厂Windows11系统恢复原厂OEM系统
  2. 52单片机——定时器2详解
  3. checkbox的点击事件
  4. Python 元祖的用法
  5. EPICS驱动NI_GPIB-ENET/1000并控制Keithley_6517A
  6. HihoCoder 1835 K-Dimensional Foil II ICPC2018 北京网络赛
  7. 织梦去除底部版权power by dedecms
  8. Linux 字符转换指令
  9. Linux无盘系统方案
  10. 想要惊艳面试官?你一张嘴就输了