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

  • 在\(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 复习小结相关推荐

  1. Tarjan算法小结1——SCC

    引入 许多最短单源路径算法,如Dijkstra,SPFA, floyd, Bellman-Ford等,在运用时只能给出指定点到任意点的最短距离,抑或是给出图中是否有环的信息,并不能准确确定环的个数.包 ...

  2. 软件构造复习小结(2)——设计规约(Specification)

    一.方法(Method) "方法"是程序的"积木",可以被独立开发.测试.复用:使用"方法"的客户端,无需了解方法内部具体如何工作- &qu ...

  3. Hello Tarjan ---- Tarjan算法小结

    一种由Robert Tarjan提出的求解有向图强连通分量的线性时间的算法.  ------百度百科 解读一下这句话,Tarjan算法可以解决存在强连通分量的图,而且是在线性时间内解决.所以,不得不% ...

  4. 工程硕士考试复习小结

                工程硕士考试复习到现在已经接近尾声,后天就要奔赴省城石家庄赶考了.整个工程硕士的复习过程从十月初开始到现在将近一个月的时间,对所需要进行考试的科目进行整体复习.复习的形式前阶段 ...

  5. 9203复习小结 消息框 新窗体

    事件 1,自定义事件 选中控件 点击闪电按钮 选中想要的事件 右边 输入一个方法名称 2,控件的默认事件 双击控件 关于窗体对象 一般情况下,窗体类中的this,代表了窗体本身 关闭闭体 this.C ...

  6. AngularJS复习小结

    开发移动端App,首先得在头部 <meta name="viewport" content="width=device-width, initial-scale=1 ...

  7. 数据库原理及应用期末复习小结

    数据库(DataBase):相互之间有关系若干的表(Table)的集合 数据库管理系统(DBMS):Database Management System,主要是指MySQL.SQL server等一系 ...

  8. 线代复习小结 矩阵等价、相似、合同的区别以及向量组等价 2019/09/13

    向量组等价: 向量组等价<=>可以相互表出 向量组等价=>等秩 但是项链组等秩≠>向量组等价 向量组等价,则该向量组的秩相同,从而A矩阵跟B矩阵的秩相同,所以矩阵A跟矩阵B等价 ...

  9. 软件设计师数据结构之线性结构复习小结

    1.1 线性表的定义 一个线性表是n(n>=0)个元素的有限序列,通常表示为(a1,a2,a3-,an).非空线性表的特点如下: 1)存在唯一的表头和表尾 2)除第一个元素外,序列中的每个元素均 ...

最新文章

  1. 【设计模式】三大类:创建型模式、结构型模式、行为型模式
  2. C#里partial关键字的作用(转摘)
  3. SAP外向交货单中的批次拆分应用于免费货物的小问题
  4. javascript中构造函数的说明
  5. WaitForMultipleObjects函数有效值分析
  6. 大数据与商业地理分析
  7. 真正开源erp,良心团队。点可云ERP
  8. eclipse汉化-设置语言包
  9. QT实现MQTT客户端
  10. MATLAB---画三角函数图像
  11. 小微企业名录geetest破解验证
  12. 具体案例 快速原型模型_快速原型模型
  13. 如何像Uber一样给工程师派单 解放外包落后的生产力
  14. Actor模型与传统模型
  15. 搭建es+kabana
  16. Deep Match to Rank Model for Personalized Click-Through Rate Prediction
  17. 手握13本书、老司机超出120年经验的公众号
  18. 一个月考过软件测评师,我是怎么做到的
  19. Python 爬虫实战1.0
  20. later与late 的区别

热门文章

  1. cisco 双ISP线路接入 链路自动切换方案
  2. MATLAB 数据分析方法(第2版)1.3 MATLAB基本语法
  3. Windows Service方式启动的Tomcat如何配置PermGen Space
  4. 如何让PhpStorm同时打开多个项目?(多项目并存的问题)
  5. socket传输过程
  6. UIImagePikerController 浅析
  7. SGU101 求有重边的无向图欧拉迹
  8. 【转】CSS 与 HTML5 响应式图片
  9. Linux下MONO执行C#程序
  10. 【android9.0】system/core下的usbhost模块无法输出log到logcat