您的位置:首页 > 其它

ACM_Tarjan

2015-11-25 17:34 232 查看

前言

Tarjan: 适用范围

计算 1.割顶

2.割边

3.计算无向图的双连通分量

4.计算有向图的连通分量

tarjan算法

首先介绍几种概念

DFS森林: 集训队的学长以及我们平时讨论的DFS森林的意思一般是几棵DFS树, 然后问了一下, 学长说大家懂就好(囧), 其实DFS森林指的是一些图(无向或者有向都可以), 不一定是树, 而且可以是多个图, 这个在刘汝佳的算法指南以及我在网上百度上给出的例子都是这个, 不过给的解释都很少, 或许不是很重要吧, 这里讲的DFS森林指的是一些图

树边(tree edge) : DFS森林中的边称为树边(所有边都是树边) #如图三的所有线

反向边(bcak edge): 第一次处理时从后代指向祖先的边被称为反向边(这个在你建了树之后才能有) #入图四的绿色线

强连通图: 在一个强连通图中,任意两个点都通过一定路径互相连通。比如图一是一个强连通图,而图二不是。因为没有一条路使得点4到达点1、2或3。



强连通分量: 在一个非强连通图中极大的强连通子图就是该图的强连通分量。比如图三中子图{1,2,3,5}是一个强连通分量,子图{4}是一个强连通分量。



割顶: 如果删除这个点, 连通分量增加, 这个点就是割顶

割边: 如果删除这个边, 连通分量增加, 这条边就是割边



图三



图四

基本概念介绍完了, 剩下的是用tarjan算各种东西了

首先tarjan包含的几个参数

dfn[i]: 代表的是进行DFS搜索的时间戳 如图中的蓝色数字



low[i]: 代表i点能向上走到的最高的点, 比如图四中low[J] = 3, low[B] = 2, low[D] = 6……

tarjan与割顶和割边

先给出代码 具体后面再解释



如图tarjan是一个dfs搜索树, 这里用链式前向星存的边, 当然也可以邻接表, dfn[i]不用解释: 肯定每次进入DFS的时候就记录该点的时间戳, 而low[i]有两种更新方式:1. 如果说一个点u的儿子v能够返回他祖先, 那么这个点能向上达到的高就可能被更新比如图死中的I点它应该等于low[I], low[J]的最小值, 2. 如果一个点的儿子是他的祖先(感觉好奇怪)那么这个点能到达的最高出 也可能被更新;
PS: 这里的DFS特点是从下向上更新, (一个点, 只有它的儿子更新了才更新他, 当然如果它本身符合情况2另当别论)
现在我们已经得到了dfn和low数组;
如何得知一个点是割点呢? 只要他的dfn[x] == low[x]就可以了, 只要满足这个条件, 说明肯定这个x点只有1个边到他的祖先, 去掉就成了两个连通图了;同理割边


tarjan与强连通分量

强连通分量的概念上面已经给出;

这里可以结合上面的割顶的特征; 割顶之下肯定是一些强连通分量(注意是从下向上更新的, 所以强连通分量会一个一个的求出, 所以我们把下面的强连通分量求出来之后, 再求这个割顶下面的强连通分量, 求出来的强连通分量肯定是一个一个的)有了割顶不难理解 直接代码



这里用栈来储存每个点, 每次DFS的时候PUSH, 在遇到割顶的时候将这里的点取出记录他们连通分量编号;(图中的do while部分)

tarjan与缩点

只要每个数有了强连通的编号 我们就可以缩点了

我们加边的时候记录一下每个边的端点



然后tarjan一次得到每个点的bcc编号

然后缩点(就是重新加边)



我们再跑DFS的时候这就是一棵树了(也可能是多棵树)如此就完成了缩点
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  tarjan