ACM_Tarjan

前言

Tarjan: 适用范围
计算 1.割顶
2.割边
3.计算无向图的双连通分量
4.计算有向图的连通分量

tarjan算法

首先介绍几种概念
DFS森林: 集训队的学长以及我们平时讨论的DFS森林的意思一般是几棵DFS树, 然后问了一下, 学长说大家懂就好(囧), 其实DFS森林指的是一些图(无向或者有向都可以), 不一定是树, 而且可以是多个图, 这个在刘汝佳的算法指南以及我在网上百度上给出的例子都是这个, 不过给的解释都很少, 或许不是很重要吧, 这里讲的DFS森林指的是一些图
树边(tree edge) : DFS森林中的边称为树边(所有边都是树边) #如图三的所有线
反向边(bcak edge): 第一次处理时从后代指向祖先的边被称为反向边(这个在你建了树之后才能有) #入图四的绿色线
强连通图: 在一个强连通图中,任意两个点都通过一定路径互相连通。比如图一是一个强连通图,而图二不是。因为没有一条路使得点4到达点1、2或3。
ACM_Tarjan_第1张图片
强连通分量: 在一个非强连通图中极大的强连通子图就是该图的强连通分量。比如图三中子图{1,2,3,5}是一个强连通分量,子图{4}是一个强连通分量。
ACM_Tarjan_第2张图片

割顶: 如果删除这个点, 连通分量增加, 这个点就是割顶
割边: 如果删除这个边, 连通分量增加, 这条边就是割边
ACM_Tarjan_第3张图片
图三
ACM_Tarjan_第4张图片
图四
基本概念介绍完了, 剩下的是用tarjan算各种东西了
首先tarjan包含的几个参数
dfn[i]: 代表的是进行DFS搜索的时间戳 如图中的蓝色数字
ACM_Tarjan_第5张图片
low[i]: 代表i点能向上走到的最高的点, 比如图四中low[J] = 3, low[B] = 2, low[D] = 6……

  1. tarjan与割顶和割边
    先给出代码 具体后面再解释
    ACM_Tarjan_第6张图片

    如图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个边到他的祖先, 去掉就成了两个连通图了;同理割边
    
  2. tarjan与强连通分量
    强连通分量的概念上面已经给出;
    这里可以结合上面的割顶的特征; 割顶之下肯定是一些强连通分量(注意是从下向上更新的, 所以强连通分量会一个一个的求出, 所以我们把下面的强连通分量求出来之后, 再求这个割顶下面的强连通分量, 求出来的强连通分量肯定是一个一个的)有了割顶不难理解 直接代码
    ACM_Tarjan_第7张图片
    这里用栈来储存每个点, 每次DFS的时候PUSH, 在遇到割顶的时候将这里的点取出记录他们连通分量编号;(图中的do while部分)

  3. tarjan与缩点
    只要每个数有了强连通的编号 我们就可以缩点了
    我们加边的时候记录一下每个边的端点
    ACM_Tarjan_第8张图片
    然后tarjan一次得到每个点的bcc编号
    然后缩点(就是重新加边)
    ACM_Tarjan_第9张图片
    我们再跑DFS的时候这就是一棵树了(也可能是多棵树)如此就完成了缩点

你可能感兴趣的:(图论)