开始学tarjan的时候,有关无向图的割点、桥、点双边双缩点都比较容易地理解了,唯独对有向图的缩点操作不甚明了。通过对luoguP2656_采蘑菇一题的解决,大致搞清了tarjan算法的正确性。

  首先放出有向图缩点tarjan函数的写法:

  1. void tarjan(int u) {
  2. dfn[u] = low[u] = ++timer;
  3. sta[++stp] = u, ins[u] = true;
  4. for (int i = head[u]; i; i = edge[i].nxt) {
  5. int v = edge[i].to;
  6. if (!dfn[v]) {
  7. tarjan(v);
  8. low[u] = min(low[u], low[v]);
  9. } else if (ins[v])
  10. low[u] = min(low[u], dfn[v]);
  11. }
  12. //////////////分割线////////////////
  13. if (dfn[u] == low[u]) {
  14. ++cnt;
  15. int x;
  16. do {
  17. x = sta[stp--];
  18. c[x] = cnt;
  19. ins[x] = false;

} while (x != u);

  1. }
  2. }

  问题主要出在函数的第二部分。遍历完u点的所有边后,第一,为什么将(dfn[u] == low[u])作为构成强连通分量的判定条件?第二,为什么此刻留在栈中的在u之后遍历的点能够构成一个强连通分量?

  我们先来考虑一个强连通分量的特征。当有向图中一些点构成的集合是强连通的,当且仅当这部分图满足其中任意两点u、v互通。容易联想到,具有这个特征的典型结构还有有向环;实际上,环是最简单的强连通图,而(感性上)任意一个强连通分量都可以理解成是若干个互通的简单环所构成的。这是一个很重要的想法。笔者认为把复杂的强连通分量简化为环来理解,可以较容易地说明tarjan算法的正确性。

  现在我们用两个简单的示意图来说明问题。

如上图,图一表示最简单的环情况,u是当前tarjan函数的起点。我们首先递归地将a、b、c入栈,发现三者的low值都指向了其上的u点,而不是它们自身。tarjan算法对条件(dfn[u] == low[u])的阐述是:满足该条件的u,是某个强连通分量的“根”;换言之,以u为根的搜索子树共同构成一个强连通分量。那么,我们观察这个结论的正确性何在。

1、对于该子树内的两点,若满足i点的时间戳大于j点,则i一定可以通过“前向边”(搜索边)连通至j点,这是显然的。

2、那么,为什么j点又可以通往i点呢?这就是判断条件(dfn[u] == low[u])的由来。显然,j点可以经由最后c点返回u点的那一条边,再从根u沿着前向边到达任意一个i点。

  同时,我们可以说明以u为根的原因:如果我们在脑补一条边c-->a,那么a、b、c三点也是强连通的,但是这个连通部分又与u强连通,那么这三点构成的集合便不能成为(极大)强连通分量,a不是“根”。反之,若以u为根的子树不能回溯到还在栈中的更高点而仅能到达u,则这个分量一定是完整的。

  图二为子树含两个环的情况,可以认为是更复杂的强连通分量结构。依然,对子树中任意一点v都可以返回到u,然后到达分量中的任意一点,则两个环共同与u构成强连通分量。实际上,任意的强连通结构都符合这个特征,我们总能沿着某条路径回到根,然后到达任意点,而这正是强连通分量的定义。

  最后,联想到维护栈的意义:若某些点已经被遍历过而不在栈中,则其参与构成的强连通分量必然已达到最大,不可能与栈中剩余点强连通。典型的例子是横叉边:由当前点可以回到上一个强连通分量中,而那个分量却不存在边能到达当前点,否则这个点早就在那个分量中就被前向边遍历过了。而对于子树中已经弹出的点,一定是各自构成了较小的强连通分量:因为一定存在某个子节点v,使得(dfn[v] == low[v]),即其子树不能回溯到更广的分量范围中。

  可能写得有些啰嗦,不太好明白(只有我自己知道我在说什么),所以欢迎有问题或者其他想法的同学在评论区交流。

对Tarjan——有向图缩点算法的理解的更多相关文章

  1. Reachability from the Capital(Codeforces Round #490 (Div. 3)+tarjan有向图缩点)

    题目链接:http://codeforces.com/contest/999/problem/E 题目: 题意:给你n个城市,m条单向边,问你需要加多少条边才能使得从首都s出发能到达任意一个城市. 思 ...

  2. POJ1523(割点所确定的连用分量数目,tarjan算法原理理解)

    SPF Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 7406   Accepted: 3363 Description C ...

  3. Tarjan的缩点&&割点概述

    What is Tarjan? Tarjan,是一种用来解决图的联通性的一种有效途径,它的一般俗称叫做:缩点.我们首先来设想一下: 如果我们有一个图,其中A,B,C构成一个环,那么我们在某种条件下,如 ...

  4. POJ2186(有向图缩点)

    Popular Cows Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 28379   Accepted: 11488 De ...

  5. POJ1904(有向图缩点+输入输出挂参考)

    King's Quest Time Limit: 15000MS   Memory Limit: 65536K Total Submissions: 8311   Accepted: 3017 Cas ...

  6. BZOJ1179 [Apio2009]Atm Tarjan 强连通缩点 动态规划

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1179 题意概括 有一个有向图,每一个节点有一个权值,其中有一些结束点. 现在,你要从S出发,到达任 ...

  7. hdu 1269 迷宫城堡 最简单的联通图题 kosaraju缩点算法

    迷宫城堡 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Problem Des ...

  8. tarjan算法和Kosaraju算法

    tarjan算法和Kosaraju算法是求有向图的强连通分量的算法: #include<iostream> #include<cstring> using namespace ...

  9. hdu 3072 有向图缩点成最小树形图计算最小权

    题意,从0点出发,遍历所有点,遍历边时候要付出代价,在一个SCC中的边不要付费.求最小费用. 有向图缩点(无需建立新图,,n<=50000,建则超时),遍历边,若不在一个SCC中,用一个数组更新 ...

随机推荐

  1. 【译】值得推荐的十大React Hook 库

    十大React Hook库 原文地址:https://dev.to/bornfightcompany/top-10-react-hook-libraries-4065 原文作者:Juraj Pavlo ...

  2. Mybatis入门 Mybatis存在的意义 解决的问题 基本操作

    Mybatis入门 Mybatis的作用 解决的问题 基本操作 为什么要学MyBatis 我们链接操作数据库需要做的步骤 package Test; import java.sql.*; public ...

  3. Java学习的第二十五天

    1.字节流输出内容 用字节流读文件内容 字符输出流写入 字符输入流 2.没问题 3.明天学习到缓冲流

  4. Java实现评论回复功能

    目录 一.分类方式 1.单一型 2.嵌套型 3.两层型 二.实现原理 1.单一型 2.嵌套型 3.两层型 使用递归循环开发评论回复功能,适用于大部分的简单单体应用 评论功能或许是大多数的单体应用之中会 ...

  5. 我用 Python 撸了一个 plist 图集拆图工具!附上github源码

    这些年,我一直在使用 JavaScript .CocosCreator 做开发,只要是他们不能解决的,我都不太愿意去弄,或者说是不太情愿去做.真的是手中有把锤子,看什么都是钉子,越是熟悉一样东西,越容 ...

  6. Mybatis之plugin插件设计原理

    大多数框架,都支持插件,用户可通过编写插件来自行扩展功能,Mybatis也不例外. 我们从插件配置.插件编写.插件运行原理.插件注册与执行拦截的时机.初始化插件.分页插件的原理等六个方面展开阐述. 一 ...

  7. 微信小程序授权页面

    这里也是比较简单的 直接复制粘贴就可以用,可能图片位置不对.. <template> <view id="imporwer"> <image src= ...

  8. c# 生成xml的结构 专业代码

    详细看代码把 public ArrayList kepingyi(string names="") { ArrayList list = new ArrayList(); stri ...

  9. php 获取抖音id

    <?php public function getid($dy_url){ $header=get_headers($dy_url); $str = "/^.*?(\d+).*/&qu ...

  10. 实验3ss

    1.实验任务1 #include <math.h> #include <stdio.h> int main() { float a,b,c,x1,x2; float delta ...