暑假刷了一堆Tarjan题到头来还是忘得差不多。

这篇博客权当复习吧。

一些定义

无向图

割顶与桥 (划重点)

图G是连通图,删除一个点表示删除此点以及所有与其相连的边。

若删除某点u后G不再连通,那么u是G的一个割顶(割点)。

若删除某边e后G不再连通,那么e是G的一个

双连通

一个图为双连通,意思是说任一点对(u,v),从u到v都有两条路径。

广义双连通有两种:点双连通(狭义的双连通)、边双连通。

  • 点双连通:就是这两条路径除了起点和终点外无重复点。
  • 边双连通:就是这两条路径无重复边。

例如,两个简单环共一个点的图是边双连通的,但不是点双连通的。

双连通图的性质

点双连通图删除任意一个点仍然连通。

边双连通图删除任意一条边仍然连通。

双连通分量

双连通分量也分为两种。

图G的双连通分量也是G的子图,且保证添加任意其他点、边后都不再是双连通的。

一个顶点可以属于多个点双连通分量,此时这个顶点必定是割顶。

显然,点双连通分量必定是边双连通分量。

哈密顿回路和欧拉回路

哈密顿路是经过所有顶点一次的路径。若起点和终点相同则称哈密顿回路。

欧拉路是经过所有边一次的路径。

有向图

有向图的连通性

  • 强连通:任意点对(u,v),存在从u到v的路径从v到u的路径。
  • 单连通:任意点对(u,v),存在从u到v的路径从v到u的路径。亦称单向连通。
  • 弱联通:忽略边的方向得到的无向图是连通的。此无向图称为该有向图的底图。

单连通图一定是弱连通图。反之则不然。

强连通分量(SCC)(划重点)

亦如上面的定义。有向图G的一个强连通分量是G的一个子图,且任意添加其他点、边都不能再满足强连通的要求。

Tarjan算法

Tarjan求割顶

首先从根节点开始dfs遍历全图,对于每个点我们定义两个数组:\(dfn[],low[]\),其中\(dfn[]\)是这个点的时间戳,用来记录首次访问这个点的时刻;而\(low[]\)则是用来记录从这个点出发所能到达点的最小时间戳。可以配合注释食用。

void tarjan(int u,int fath){
dfn[u]=low[u]=++tmp;
int child=0;
for (int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if (!dfn[v]){//如果在此之前点v没有被访问过
tarjan(v,u);
low[u]=Min(low[u],low[v]);//更新最小时间戳
child++;
if (!fath&&child>=2) rec[v]=1;//如果u为根节点且u下有两棵子树那么u一定是割顶
else (fath&&(low[v]>=dfn[u])) rec[v]=1;//如果u有子树的最小时间戳不小于u的时间戳,那么u一定是割顶
}else{
if (u!=fath) low[u]=Min(low[u],dfn[v]);//v的时间戳可能比u小,并且回边不能算
}
}
}

Tarjan求桥

和求割顶非常类似

void tarjan(int u,int fath){
dfn[u]=low[u]=++tmp;
int child=0;
for (int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if (!dfn[v]){
tarjan(v,u);
low[u]=Min(low[u],low[v]);
child++;
if (dfn[u]<low[v]){e[++cnt].u=u;e[cnt].v=v;}
}else {if (u!=fath) low[u]=Min(low[u],dfn[v]);}
}
}

Tarjan求强连通分量

在Tarjan求强连通分量的过程中,low的定义有所改变,并且引入一个栈,low不是能到达的最前的dfn值,而是能到达的仍在栈中的dfn的最前值。

void tarjan(int u){
dfn[u]=low[u]=++timer;
st.push(u); instack[u]=true;
for (int i=0;i<e[u].size();i++) {
int v=e[u][i];
if (dfn[v]==0) {//如果访问过v
tarjan(v);
low[u]=min(low[u],low[v]);//更新最小时间戳
} else if (instack[v]) {//如果在栈内(在同一个强连通分量内)
low[u]=min(low[u],dfn[v]);
/*同low[u]=min(low[u],low[v]);
LXQ:求scc应该都可以-.-因为你一旦找到了上一个scc那它们就都出栈了-.-所以后面更新判断是否在栈中就保证了更新的值都是可行的
求scc不存在割顶的问题所以应该都可以
Upd.其实就是说已经走过的v在栈内,但是由于递归没有回溯,所以此时dfn[v]==low[v]*/
}
}
if (dfn[u]==low[u]) {//这就是一个强连通分量的根节点
int m;
printf("SCC: ");
do {
m=st.top();
st.pop();/*使栈顶出栈,把该强连通分量内除根节点外的
所有点弹出*/
instack[m]=false;
printf("%d ",m);
} while (m!=u);
printf("\n");
}
}

缩点

一般,缩点是针对有向图而言的。

找出了一个有向图的强连通分量后我们可以把每个强连通分量缩为一个点。

如此一来我们便得到一个有向无环图(DAG)。

有了有向无环图,我们就可以在上面跑拓扑。能跑拓朴就能跑dp,因为状态转移的无后效性已经在DAG建立的同时保证了。

例题:

  1. Luogu_3627_[APIO2009]抢掠计划

    一句话题解:对于题目中的起点S的处理,在跑Tarjan的时候记录访问过的点,缩点的时候把没访问过的点排除即可。

练习:

Tarjan缩点+DAG+dp模板题:

Luogu_3387_【模板】缩点

Luogu_4742_[Wind Festival]Running In The Sky

图论初步-Tarjan算法及其应用的更多相关文章

  1. 图论1 Tarjan算法

    强连通分量 模板(强联通分量个数+缩点) #include<iostream> #include<cstdio> #define MAXn 100000 #define MAX ...

  2. 图论:Tarjan算法

    在有向图中,若两点至少包含一条路径可以到达,则称两个顶点强连通,若任意两个顶点皆如此,则称此图为强联通图.非强连通图有向图的极大强连通子图,称为强连通分量(strongly connected com ...

  3. 『图论』有向图强连通分量的Tarjan算法

    在图论中,一个有向图被成为是强连通的(strongly connected)当且仅当每一对不相同结点u和v间既存在从u到v的路径也存在从v到u的路径.有向图的极大强连通子图(这里指点数极大)被称为强连 ...

  4. 【原创】tarjan算法初步(强连通子图缩点)

    [原创]tarjan算法初步(强连通子图缩点) tarjan算法的思路不是一般的绕!!(不过既然是求强连通子图这样的回路也就可以稍微原谅了..) 但是研究tarjan之前总得知道强连通分量是什么吧.. ...

  5. 【算法•日更•第二十八期】图论:强连通+Tarjan算法(一)

    ▎前言 一直都想学习这个东西,以为很难,结果发现也不过如此. 只要会些图论的基础就可以了. ▎强连通 ☞『定义』 既然叫强连通,那么一定具有很强的连通性. 强连通:就是指在一个有向图中,两个顶点可以互 ...

  6. ACM(图论)——tarjan算法详解

    ---恢复内容开始--- tarjan算法介绍: 一种由Robert Tarjan提出的求解有向图强连通分量的线性时间的算法.通过变形,其亦可以求解无向图问题 桥: 割点: 连通分量: 适用问题: 求 ...

  7. 图论分支-Tarjan初步-割点和割边

    所谓割点(顶)割边,我们引进一个概念 割点:删掉它之后(删掉所有跟它相连的边),图必然会分裂成两个或两个以上的子图. 割边(桥):删掉一条边后,图必然会分裂成两个或两个以上的子图,又称桥. 这样大家就 ...

  8. 图论-强连通分量-Tarjan算法

    有关概念: 如果图中两个结点可以相互通达,则称两个结点强连通. 如果有向图G的每两个结点都强连通,称G是一个强连通图. 有向图的极大强连通子图(没有被其他强连通子图包含),称为强连通分量.(这个定义在 ...

  9. Light OJ - 1026 - Critical Links(图论-Tarjan算法求无向图的桥数) - 带详细注释

     原题链接   无向连通图中,如果删除某边后,图变成不连通,则称该边为桥. 也可以先用Tajan()进行dfs算出所有点 的low和dfn值,并记录dfs过程中每个 点的父节点:然后再把所有点遍历一遍 ...

随机推荐

  1. u-boot中filesize环境变量【转载】

    转载地址:https://blog.csdn.net/fzs333/article/details/48518559 U-Boot中的环境命令可以使用$(filesize)来确定刚下载(传输)得到的文 ...

  2. 用Chrome网页获取PDF?

    在网页浏览的时候,我常常想保存网页上的内容 这时候有几种选择,要么copy and paste,要么windows自带截图,要么就是借用tencent的截图工具... 但是对于一些用chrome预览的 ...

  3. 应用gis笔记

    接口,开发包??我要做一个移动端的,完了之后和5G挂一下钩, web/桌面/移动 C#就是.NET.... 和专业程序设计课程的区别 a kind of boring hope it helpful, ...

  4. spark shc hbase 超时问题 hbase.client.scanner.timeout.period 配置

    异常信息 20/02/27 19:36:21 INFO TaskSetManager: Starting task 17.1 in stage 3.0 (TID 56, 725.slave.adh, ...

  5. js中call和apply的实现原理

    js中call和apply的实现原理            实现call的思路: /* 还有就是call方法是放在Function().prototype上的也就是构造函数才有的call方法 (我门可 ...

  6. 新手学习Web前端的三个高效学习方法,基础要重视

    作为新手,出于对风险的担心,不免在学习一项新技能或者转投一个新行业的时候,有所犹豫与徘徊.毕竟,在这场类似冒险的选择中,我们需要投入时间.精力以及承受相关的经济损失.但是,只有勇敢迈出第一步,才能为生 ...

  7. Go-语言基础-变量-类型-函数

    第一个程序 //单行注释 /* 多行注释 */ package main // 表示当前go文件属于main包 import "fmt" // 导入包 //编译型语言需要有一个入口 ...

  8. 5.docker image (镜像)

    1.image 是什么 是文件和 meta data 的集合 (root filesystem) 是分层的,并且每一层都可以添加改变删除文件,成为一个新的image 不同的image可以共享相同的la ...

  9. JavaScript面试题(珍爱生命,远离面试)

    1.使用 typeof bar === "object" 判断 bar 是不是一个对象有神马潜在的弊端?如何避免这种弊端? 使用 typeof 的弊端是显而易见的(这种弊端同使用 ...

  10. 17.3.13---sys.argv[]用法

    1------sys.argv[]是用来获取命令行参数, sys.argv[0]表示代码本身文件路径,因此要从第二个即sys.argv[1]开始去参数 例如创建一个文件: import sys pri ...