• 总算把这几个东西策清楚了。

  • 在\(Tarjan\)算法里面,有两个时间戳非常重要,一个是\(dfn\),意为深度优先数,即代表访问顺序;一个是\(low\),意为通过反向边能到达的最小\(dfn\),也就是最强反祖能力。

  • 注意,强联通分量只存在于有向图中,割点,桥,点双,边双是无向图的概念。

一、割点。

  • [x] 模板题

  • 割点:一个结点称为割点,当且仅当去掉该节点和其相关的边之后的子图不连通。

  • 针对无向图。

  • 首先我们考虑一个连通图(非连通图可以分别考虑连通块),我们从任意一个起点开始进行深度优先搜索,可以得到一棵树,并且这棵树中所有结点的子树之间不存在边,即没有跨越两棵子树的边

  • 考虑一下,如果存在,那么与深度优先搜索树的定义互相矛盾。

  • 于是有如下定理:

    在无向连通图\(G\)中,

    1、根结点\(u\)为割顶当且仅当它有两个或者多个子结点;

    2、非根结点\(u\)为割顶当且仅当u存在结点v,使得\(v\)与其所有后代都没有反向边可以连回\(u\)的祖先。可以简单写成\(dfn_u\leq low_v\)

  • 贴个代码

void Tarjan(R i,R rt){
R sum=0;dfn[i]=low[i]=(++cnt);
for(R k=hd[i];k;k=nt[k]){
if(!dfn[to[k]]){
Tarjan(to[k],rt),low[i]=min(low[i],low[to[k]]);
if(i==rt)sum++;
else if(low[to[k]]>=dfn[i])ans[i]=1;
}
else low[i]=min(low[i],dfn[to[k]]);
}
if(i==rt&&sum>1)ans[i]=1;
} 注意 在不联通图中,应当
for(R i=1;i<=n;++i)if(!dfn[i])Tarjan(i,i);
这样才能保证全部求到,注意根节点.

二、桥。

  • 针对无向图。
  • 桥的求法其实也是类似的,它的求法可以看成是割顶的一种特殊情况.
  • 当结点\(u\)的子结点\(v\)的后代通过反向边只能连回\(v\),那么删除这条边\((u, v)\)就可以使得图\(G\)非连通了。用\(Tarjan\)算法里面的时间戳表示这个条件,就是\(low_v>dfn_u\)。
  • 注意更新\(low\)时是特判不能使用来的反边。
  • 不需要单独考虑根节点的情况。
  • 贴个代码
void Tarjan(R i,R id){
dfn[i]=low[i]=(++cnt);
for(R k=hd[i];k;k=nt[k]){
if(k==(id^1))continue; 无向图中,这样的边是不能被遍历的。
if(!dfn[to[k]]){
Tarjan(to[k],k),low[i]=min(low[i],low[to[k]]);
if(low[to[k]]>dfn[i])G[++tot]=k; k这条边即为桥。
}
else low[i]=min(low[i],dfn[to[k]]);
}
}

三、强联通和双联通一点区别。

  • 链接

  • 所谓双连通与强连通,最大的差别,也是最本质的差别就是后者适用于无向图中,而前者适用于有向图。至于两者的概念是一样的,就是图中有a点、b点,从a点可到达b点,同时从b点可到达a点。

四、强联通分量。

  • 而为了存储整个强联通分量,这里挑选的容器是栈。

  • 每次一个新节点出现,就进,如果这个点有出度就继续往下找。

  • 每次返回上来都看一看子节点与这个节点的\(low\)值,谁小就取谁,保证最小的子树根。

  • 如果找到\(low==dfn\),说明这个节点是这个分量的根节点。

  • 最后找到分量的节点后,就将这个栈里,它们就组成一个全新的分量。

  • 具体实现的时候,如果这条边是往下的边,就用他的\(low\)去更新现在的\(low\)

  • 否则,如果这条边指向了栈内的点,就用他的\(dfn\)去更新现在的\(low\)

  • 为什么要特别判断是否是栈内的点呢?因为只有栈内的点才可以到达当前点。在有向图中,如果指向的点不在栈内,他也就无法到达当前点,不可能组成强联通。

  • 判断\(low==dfn\)是在\(for\)循环外面进行的。

  • 贴个代码

void Tarjan(R i){
low[i]=dfn[i]=(++cnt),vis[i]=1,Q[++tp]=i;
R p=tp;
for(R k=hd[i];k;k=nt[k]){
if(!dfn[to[k]])Tarjan(to[k]),low[i]=min(low[i],low[to[k]]);
else if(vis[to[k]])low[i]=min(low[i],dfn[to[k]]);
}
if(dfn[i]==low[i]){
tot++;
for(R j=p;j<=top;++j)vis[Q[j]]=0,bel[Q[j]]=tot;
tp=p-1;
}
}

五、边双。

  • 其实就是一个求桥的过程。
  • 一个桥把联通块分成了两个部分,这两个部分是独立的两个边双。
  • 贴个代码
void Tarjan(R i,R id){
dfn[i]=low[i]=(++cnt);
for(R k=hd[i];k;k=nt[k]){
if(k==(id^1))continue;
if(!dfn[to[k]]){
Tarjan(to[k],k),low[i]=min(low[i],low[to[k]]);
if(low[to[k]]>dfn[i])vis[k]=vis[k^1]=1; 标记
}
else low[i]=min(low[i],dfn[to[k]]);
}
}
upd on 10.31
  • 另外一种写法:
  • 或者类似于有向图的强联通分量,区别在于:
  • 强制不走回头路。
  • 不需要考虑是否在栈内。
void Tarjan(R i,R op){
low[i]=dfn[i]=(++cnt),Q[++tp]=i;R p=tp;
for(R k=hd[i];k;k=nt[k]){
if(k==op^1)continue;
if(!dfn[to[k]])Tarjan(to[k],k),low[i]=min(low[i],low[to[k]]);
else low[i]=min(low[i],dfn[to[k]]);
}
if(dfn[i]==low[i]){
tot++;
for(R j=p;j<=top;++j)bel[Q[j]]=tot;
tp=p-1;
}
}

六、点双

  • 其实就是一个求割点的过程。
  • 一个割点把联通块分成了两个部分,这两个部分是独立的两个点双。
  • 贴个代码
void Tarjan(R i,R rt){
R sum=0;dfn[i]=low[i]=(++cnt);
for(R k=hd[i];k;k=nt[k]){
if(!dfn[to[k]]){
Tarjan(to[k],rt),low[i]=min(low[i],low[to[k]]);
if(i==rt)sum++;
else if(low[to[k]]>=dfn[i])ans[i]=1;
}
else low[i]=min(low[i],dfn[to[k]]);
}
if(i==rt&&sum>1)ans[i]=1;
}
  • 和割点的代码是一样的,只是最后\(Dfs\)找到所有点双,注意,一个割点会存在于多个点双内。

七、小清新水题。

Tarjan 复习小结的更多相关文章

  1. tarjan复习笔记

    tarjan复习笔记 (关于tarjan读法,优雅一点读塔洋,接地气一点读塔尖) 0. 连通分量 有向图: 强连通分量(SCC)是个啥 就是一张图里面两个点能互相达到,那么这两个点在同一个强连通分量里 ...

  2. 设计模式复习小结一(Strategy Pattern/Observer Pattern/Decorator Patter/Factory Pattern)

    目录: 前言 1. Stratrgy Pattern 2. Observer Pattern 3. Decorator Pattern 4. Factory Pattern 4.1 FactoryPa ...

  3. NOIP 考前 Tarjan复习

    POJ 1236 给定一个有向图,求: 1) 至少要选几个顶点,才能做到从这些顶点出发,可以到达全部顶点 2) 至少要加多少条边,才能使得从任何一个顶点出发,都能到达全部顶点 第一个就是缩点之后有多少 ...

  4. tarjan复习笔记 双连通分量,强连通分量

    声明:图自行参考割点和桥QVQ 双连通分量 如果一个无向连通图\(G=(V,E)\)中不存在割点(相对于这个图),则称它为点双连通图 如果一个无向连通图\(G=(V,E)\)中不存在割边(相对于这个图 ...

  5. tarjan 复习笔记 割点与桥

    定义分析 给定一个无向连通图\(G=(V,E)\) 对于\(x\in Y\),如果删去\(x\)及与\(x\)相连的边后,\(G\)分裂为两个或者两个以上的不连通子图,那么称\(x\)为\(G\)的割 ...

  6. React复习小结(一)

    一.React的发展 facebook在构建instagram网站的时候遇见两个问题: 1.数据绑定的时候,大量操作真实dom,性能成本太高 2.网站的数据流向太混乱,不好控制 于是facebook起 ...

  7. html复习小结

    border-radius可以设置百分比 百分之五十是圆形 class="class1 class2" 无序列表 <ul><li></li>&l ...

  8. 数位DP复习小结

    转载请注明原文地址http://www.cnblogs.com/LadyLex/p/8490222.html 之前学数位dp的时候底子没打扎实 虚的要死 这次正好有时间……刷了刷之前没做的题目 感觉自 ...

  9. mysql查询语句复习小结

    SQL查询语句基本语法: select 字段列表 from 表名|视图列表 [where 条件表达式1] [group by 属性名1 [having 条件表达式2]] [order by 属性名2 ...

随机推荐

  1. 前端每日实战:142# 视频演示如何用 CSS 的 Grid 布局创作一枚小鸡邮票

    效果预览 按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以全屏预览. https://codepen.io/comehope/pen/mGZbmQ 可交互视频 此视频是可 ...

  2. Mysql中主键与索引

    摘自: https://www.cnblogs.com/wicub/p/5898286.html 一.什么是索引?索引用来快速地寻找那些具有特定值的记录,所有MySQL索引都以B-树的形式保存.如果没 ...

  3. 【转】gl_NormalMatrix

    关于为什么对法线变换时要使用变换矩阵的转置的逆,而不能像变换顶点那样直接使用变换矩阵 https://www.cnblogs.com/bigdudu/articles/4191042.html 注意文 ...

  4. nginx 入门 安装

    .yum解决编译nginx所需的依赖包,之后你的nginx就不会报错了 yum install gcc patch libffi-devel python-devel zlib-devel bzip2 ...

  5. mysql慢查询解析-linux命令

    使用mysqldumpslow 命令可以解析mysql慢查询日志,mysqldumpslow的参数如下: -s ,是按照任何方式排序,c.t.l.r分别是按照记录次数.时间.查询时间.返回的记录数 来 ...

  6. 在静态页面中使用 Vue.js

    在静态页面中使用 Vue.js 不使用Node.js, NPM, Webpack 等, 在静态页中使用Vue.js. 包括路由, 单文件组件. 1. 创建index.html index.html做为 ...

  7. 在自定义组件中获取spring底层组件

    要想在自定义组件中获取spring底层的各种组件,只需让自定义组件实现一系列接口即可,这些接口都是Aware的子接口.常见的有: 1. ApplicationContextAware——用于获取IOC ...

  8. Arrays.toList工具类

  9. vue打包详情

    说明 本文代码中的配置基于vue-cli2 需求 在实际开发中我们可能有测试环境一套请求API 和 正式环境一套API,尤其是两个环境的域名不同时,就需要我们分环境打不同配置的包 了解 webpack ...

  10. 解决django项目无法连接远程mysql的问题

    我们都知道django项目可以通过修改settings.py文件中的DATABASES这个对象,使用不同的数据库. 如图所示,我们想连接远程的mysql,修改settings.py的配置 然后我们在终 ...