对Tarjan——有向图缩点算法的理解
开始学tarjan的时候,有关无向图的割点、桥、点双边双缩点都比较容易地理解了,唯独对有向图的缩点操作不甚明了。通过对luoguP2656_采蘑菇一题的解决,大致搞清了tarjan算法的正确性。
首先放出有向图缩点tarjan函数的写法:
- void tarjan(int u) {
- dfn[u] = low[u] = ++timer;
- sta[++stp] = u, ins[u] = true;
- for (int i = head[u]; i; i = edge[i].nxt) {
- int v = edge[i].to;
- if (!dfn[v]) {
- tarjan(v);
- low[u] = min(low[u], low[v]);
- } else if (ins[v])
- low[u] = min(low[u], dfn[v]);
- }
- //////////////分割线////////////////
- if (dfn[u] == low[u]) {
- ++cnt;
- int x;
- do {
- x = sta[stp--];
- c[x] = cnt;
- ins[x] = false;
} while (x != u);
- }
- }
问题主要出在函数的第二部分。遍历完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——有向图缩点算法的理解的更多相关文章
- Reachability from the Capital(Codeforces Round #490 (Div. 3)+tarjan有向图缩点)
题目链接:http://codeforces.com/contest/999/problem/E 题目: 题意:给你n个城市,m条单向边,问你需要加多少条边才能使得从首都s出发能到达任意一个城市. 思 ...
- POJ1523(割点所确定的连用分量数目,tarjan算法原理理解)
SPF Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 7406 Accepted: 3363 Description C ...
- Tarjan的缩点&&割点概述
What is Tarjan? Tarjan,是一种用来解决图的联通性的一种有效途径,它的一般俗称叫做:缩点.我们首先来设想一下: 如果我们有一个图,其中A,B,C构成一个环,那么我们在某种条件下,如 ...
- POJ2186(有向图缩点)
Popular Cows Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 28379 Accepted: 11488 De ...
- POJ1904(有向图缩点+输入输出挂参考)
King's Quest Time Limit: 15000MS Memory Limit: 65536K Total Submissions: 8311 Accepted: 3017 Cas ...
- BZOJ1179 [Apio2009]Atm Tarjan 强连通缩点 动态规划
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1179 题意概括 有一个有向图,每一个节点有一个权值,其中有一些结束点. 现在,你要从S出发,到达任 ...
- hdu 1269 迷宫城堡 最简单的联通图题 kosaraju缩点算法
迷宫城堡 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Problem Des ...
- tarjan算法和Kosaraju算法
tarjan算法和Kosaraju算法是求有向图的强连通分量的算法: #include<iostream> #include<cstring> using namespace ...
- hdu 3072 有向图缩点成最小树形图计算最小权
题意,从0点出发,遍历所有点,遍历边时候要付出代价,在一个SCC中的边不要付费.求最小费用. 有向图缩点(无需建立新图,,n<=50000,建则超时),遍历边,若不在一个SCC中,用一个数组更新 ...
随机推荐
- 一起学Vue:路由(vue-router)
前言 学习vue-router就要先了解路由是什么?前端路由的实现原理?vue-router如何使用?等等这些问题,就是本篇要探讨的主要问题. vue-router是什么 路由是什么? 大概有两种说法 ...
- Serilog 源码解析——总览
背景 大家好,考虑到在最近这些天,闲来无事,找了个类库好好研究下别人写的高质量代码,颇有收获,打算和大家分享下.考虑到最近在自学 ASP.NET Core 的相关开发,对 Serilog 这个日志记录 ...
- PageHelper使用步骤
一.导入jar包(maven构建导入坐标) <dependency> <groupId>com.github.pagehelper</groupId> <ar ...
- React中useLayoutEffect和useEffect的区别
重点: 1.二者函数签名相同,调用方式是一致的 2. 怎么简单进行选择: 无脑选择useEffect,除非运行效果和你预期的不一致再试试useLayoutEffect 区别详解:useEffect是异 ...
- Nginx是什么?有什么用?
一.Nginx是什么 Nginx ("engine x") 是一个高性能的 HTTP 和反向代理服务器,特点是占有内存少,并发能力强,事实上nginx的并发能力确实在同类型的网页服 ...
- Redis的介绍及使用
redis 简介 简单来说 redis 就是一个数据库,不过与传统数据库不同的是 redis 的数据是存在内存中的,所以读写速度非常快,因此 redis 被广泛应用于缓存方向.另外,redis 也经常 ...
- 微信小程序——【百景游戏小攻略】
微信小程序--[百景游戏小攻略] 本次课程小项目中的图片以及文章还未获得授权!请勿商用!未经授权,请勿转载! 博客班级 https://edu.cnblogs.com/campus/zjcsxy/SE ...
- mysql 两主一从环境搭建(5.7.24)
搭建说明 两主一从,从本质上说,只不过是机器 master-a 和 master-b 互为主从机(热备),然后通过 keepalived 进行高可用配置,使得在同一时间内只会有一台对外提供服务,实现单 ...
- NOIP 2013 P1967 货车运输
倍增求LCA+最大生成树 题目给出的是一张图,在图上有很多算法无法实现,所以要将其转化为树 题中可以发现货车的最后的载重量是由权值最小的一条边决定的,所以我们求最大生成树 求完最大生成树后我们得到一个 ...
- 微信小程序获取二维码API
<%@ WebHandler Language="C#" Class="ce" %> using System; using System.Web; ...