Tarjan 复习小结
总算把这几个东西策清楚了。
- 在\(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\)找到所有点双,注意,一个割点会存在于多个点双内。
七、小清新水题。
- [x] 割点模板题
- [x] 桥模板题
- [x] 有向图强联通分量模板
[x] 无向图边双模板
其他题目在yl题单了。
转载于:https://www.cnblogs.com/Tyher/p/9843020.html
Tarjan 复习小结相关推荐
- Tarjan算法小结1——SCC
引入 许多最短单源路径算法,如Dijkstra,SPFA, floyd, Bellman-Ford等,在运用时只能给出指定点到任意点的最短距离,抑或是给出图中是否有环的信息,并不能准确确定环的个数.包 ...
- 软件构造复习小结(2)——设计规约(Specification)
一.方法(Method) "方法"是程序的"积木",可以被独立开发.测试.复用:使用"方法"的客户端,无需了解方法内部具体如何工作- &qu ...
- Hello Tarjan ---- Tarjan算法小结
一种由Robert Tarjan提出的求解有向图强连通分量的线性时间的算法. ------百度百科 解读一下这句话,Tarjan算法可以解决存在强连通分量的图,而且是在线性时间内解决.所以,不得不% ...
- 工程硕士考试复习小结
工程硕士考试复习到现在已经接近尾声,后天就要奔赴省城石家庄赶考了.整个工程硕士的复习过程从十月初开始到现在将近一个月的时间,对所需要进行考试的科目进行整体复习.复习的形式前阶段 ...
- 9203复习小结 消息框 新窗体
事件 1,自定义事件 选中控件 点击闪电按钮 选中想要的事件 右边 输入一个方法名称 2,控件的默认事件 双击控件 关于窗体对象 一般情况下,窗体类中的this,代表了窗体本身 关闭闭体 this.C ...
- AngularJS复习小结
开发移动端App,首先得在头部 <meta name="viewport" content="width=device-width, initial-scale=1 ...
- 数据库原理及应用期末复习小结
数据库(DataBase):相互之间有关系若干的表(Table)的集合 数据库管理系统(DBMS):Database Management System,主要是指MySQL.SQL server等一系 ...
- 线代复习小结 矩阵等价、相似、合同的区别以及向量组等价 2019/09/13
向量组等价: 向量组等价<=>可以相互表出 向量组等价=>等秩 但是项链组等秩≠>向量组等价 向量组等价,则该向量组的秩相同,从而A矩阵跟B矩阵的秩相同,所以矩阵A跟矩阵B等价 ...
- 软件设计师数据结构之线性结构复习小结
1.1 线性表的定义 一个线性表是n(n>=0)个元素的有限序列,通常表示为(a1,a2,a3-,an).非空线性表的特点如下: 1)存在唯一的表头和表尾 2)除第一个元素外,序列中的每个元素均 ...
最新文章
- 【设计模式】三大类:创建型模式、结构型模式、行为型模式
- C#里partial关键字的作用(转摘)
- SAP外向交货单中的批次拆分应用于免费货物的小问题
- javascript中构造函数的说明
- WaitForMultipleObjects函数有效值分析
- 大数据与商业地理分析
- 真正开源erp,良心团队。点可云ERP
- eclipse汉化-设置语言包
- QT实现MQTT客户端
- MATLAB---画三角函数图像
- 小微企业名录geetest破解验证
- 具体案例 快速原型模型_快速原型模型
- 如何像Uber一样给工程师派单 解放外包落后的生产力
- Actor模型与传统模型
- 搭建es+kabana
- Deep Match to Rank Model for Personalized Click-Through Rate Prediction
- 手握13本书、老司机超出120年经验的公众号
- 一个月考过软件测评师,我是怎么做到的
- Python 爬虫实战1.0
- later与late 的区别
热门文章
- cisco 双ISP线路接入 链路自动切换方案
- MATLAB 数据分析方法(第2版)1.3 MATLAB基本语法
- Windows Service方式启动的Tomcat如何配置PermGen Space
- 如何让PhpStorm同时打开多个项目?(多项目并存的问题)
- socket传输过程
- UIImagePikerController 浅析
- SGU101 求有重边的无向图欧拉迹
- 【转】CSS 与 HTML5 响应式图片
- Linux下MONO执行C#程序
- 【android9.0】system/core下的usbhost模块无法输出log到logcat