Tarjan 强连通分量 及 双联通分量(求割点,割边)

众所周知,Tarjan的三大算法分别为

(1)         有向图的强联通分量

(2)         无向图的双联通分量(求割点,桥)

(3)         最近公共祖先

今天主要给未来的自己讲解一下前两个应用,让未来的自己不会向现在的自己一样又忘了Tarjan怎么写。熟悉DFS的话,理解起来会简单很多。

(1)         有向图的强联通分量

首先解释Tarjan中几个比较重要的值

DFN[i] : 节点i被访问到的次序

LOW[i]: 节点i的子孙节点能够追溯到的次序最早的祖先节点

Stack[i]: 存储强连通分量

VIS[i]  : VIS[i] = 1 则节点在栈中,否则不在

DFN[i] == 0 时,很明显,就是该点没有被访问过

DFN[i]==LOW[i], 切换成中文,意思就是节点i被访问到的次序,是他的子孙节点中能够追溯到的最早次序,换句话说,i和i的子孙节点(并非所有子孙节点,而是所有进栈的子孙节点)构成了一个强连通分量。

接下来就是重头戏了。让我们开始DFS。

(1) Tarjan开始,对于节点u

有DFN[u] = LOW[u] = ++deep

因为第u个点第一次被访问到的时候还没有访问其子节点

把u加入栈中(将来用于回溯)并且打上VIS标记

(2) 对于u的每一条边,所访问到的v节点

如果v节点没有被访问过,那就直接回到第一步

回溯结束后(对于没有子节点的节点,可以见得它的LOW 就等于它的 DFN)

LOW[u] = min(LOW[u],LOW[v])

因为LOW[u] 要取到u的所有子节点中最小的LOW[v]值

如果v节点已经在栈中了,

直接LOW[u] = min(LOW[u],LOW[v])

同理,此时已构成环

如果v节点被访问到,且v节点不在栈中了

证明v已经出栈,不可与u点构成强联通分量

(3) DFN[i]==LOW[i]

当我们回溯到底i个点发现它满足上述条件的话,证明该点和子孙节点能够构成强联通分量。且i是最早入栈的(LOW的定义),这时候只需要退栈到栈顶不是i点就OK了。

附上一份代码,

模板Tarjan  POJ 2186

写一次就明白了

const int maxn = 150000;

struct Edge

{

int from,to,next;

}edge[maxn];

int head[maxn],DFN[maxn],low[maxn];

int Stack[maxn],vis[maxn],color[maxn],deg[maxn];

int deep,top,k,tol;

void init()

{

k = tol = top = deep = 0;

CLR(head,-1);

CLR(DFN,0);

CLR(low,0);

CLR(color,0);

CLR(Stack,0);

CLR(vis,0);

CLR(deg,0);

}

void addedge(int u,int v)

{

edge[tol].from = u;

edge[tol].to = v;

edge[tol].next = head[u];

head[u] = tol++;

}

void tarjan(int u)

{

DFN[u] = low[u] = ++deep;

vis[u] = 1;

Stack[++top] = u;

for(int i = head[u]; ~i; i = edge[i].next){

int v = edge[i].to;

if(!DFN[v]){

tarjan(v);

low[u] = min(low[v],low[u]);

}

else if(vis[v]){

low[u] = min(low[v],low[u]);

}

}

if(DFN[u] == low[u]){

color[u] = ++k;

vis[u] = 0;

while(Stack[top]!=u){

color[Stack[top]] = k;

vis[Stack[top]] = 0;

top--;

}

top--;

}

}

求割边:当LOW[V]>DFN[U]时,证明v点和它的子孙节点无法回溯到u,v间为桥

求割点:当LOW[V]>=DFN[U]时,证明v点和它的子孙节点无法回溯到u的祖先(可以回溯到u).u点为割点

根节点如果有多个子节点,则为割点

const int maxn = 1500;
struct Edge
{
int from,to,next;
int cut;
}edge[maxn];
int head[maxn],low[maxn],DFN[maxn];
int n,deep,tol,ans;
int cut_point[maxn]; void init()
{
ans = tol = deep = 0;
CLR(head,-1);
CLR(cut_point,0
CLR(DFN,0);
CLR(low,0);
} void addedge(int u,int v)
{
edge[tol].from = u;
edge[tol].to = v;
edge[tol].next = head[u];
head[u] = tol++;
} void tarjan(int u, int fa) { //u在DFS树中的父节点是fa
low[u] = DFN[u] = ++deep;
int child = 0; //子节点数目
for(int i = head[u]; ~i; i = edge[i].next) {
int v = edge[i].to;
if( fa == v ) continue;
if(!DFN[v]) {
child++;
tarjan(v, u);
low[u] = min(low[u], low[v]);
if(low[v] >= DFN[u]) {
if(low[v] > DFN[u]) edge[i].cut = 1;
cut_point[u] = 1;
}
}
else low[u] = min(low[u], DFN[v]);
}
if(fa < 0 && child == 1) cut_point[u] = 0;
} int search_cut_point()
{
tarjan(1,-1);
for(int i=1;i<=n;i++)
if(cut_point[i])
ans++;
}

Tarjan 强连通分量 及 双联通分量(求割点,割边)的更多相关文章

  1. 『Tarjan算法 无向图的双联通分量』

    无向图的双连通分量 定义:若一张无向连通图不存在割点,则称它为"点双连通图".若一张无向连通图不存在割边,则称它为"边双连通图". 无向图图的极大点双连通子图被 ...

  2. 无向图边双联通分量 tarjan 模板

    #include <bits/stdc++.h> using namespace std; const int MAXN = 100005; const int MAXM = 500005 ...

  3. 洛谷P2860 [USACO06JAN]冗余路径Redundant Paths(tarjan求边双联通分量)

    题目描述 In order to get from one of the F (1 <= F <= 5,000) grazing fields (which are numbered 1. ...

  4. POJ 2942 Knights of the Round Table 补图+tarjan求点双联通分量+二分图染色+debug

    题面还好,就不描述了 重点说题解: 由于仇恨关系不好处理,所以可以搞补图存不仇恨关系, 如果一个桌子上面的人能坐到一起,显然他们满足能构成一个环 所以跑点双联通分量 求点双联通分量我用的是向栈中pus ...

  5. POJ2942 Knights of the Round Table【Tarjan点双联通分量】【二分图染色】【补图】

    LINK 题目大意 有一群人,其中有一些人之间有矛盾,现在要求选出一些人形成一个环,这个环要满足如下条件: 1.人数大于1 2.总人数是奇数 3.有矛盾的人不能相邻 问有多少人不能和任何人形成任何的环 ...

  6. 图连通性【tarjan点双连通分量、边双联通分量】【无向图】

    根据 李煜东大牛:图连通性若干拓展问题探讨 ppt学习. 有割点不一定有割边,有割边不一定有割点. 理解low[u]的定义很重要. 1.无向图求割点.点双联通分量: 如果对一条边(x,y),如果low ...

  7. [J]computer network tarjan边双联通分量+树的直径

    https://odzkskevi.qnssl.com/b660f16d70db1969261cd8b11235ec99?v=1537580031 [2012-2013 ACM Central Reg ...

  8. poj 3177&&3352 求边双联通分量,先求桥,然后求分量( 临界表代码)

    /*这道题是没有重边的,求加几条边构成双联通,求边联通分量,先求出桥然后缩点,成一个棵树 找叶子节点的个数*/ #include<stdio.h>//用容器写在3177这个题上会超内存,但 ...

  9. hdu 3352 求边双联通分量模板题(容器)

    /*这道题是没有重边的,求加几条边构成双联通,求边联通分量,先求出桥然后缩点,成一个棵树 找叶子节点的个数*/ #include<stdio.h> #include<string.h ...

随机推荐

  1. C# System.Collections.Queue

    using System; using System.Collections; public class SamplesQueue { public static void Main() { // C ...

  2. iOS 创建一个App目录结构

    Class:存放的是App中所有的模块功能 Base:存放一些基类,比如BaseViewController,BaseModel等,共性直接在基类中去修改 Vendor:三方,因为我的项目中使用coc ...

  3. linux 下的emoji在MariaDB中的字符集修改

    在此目录下修改这个文件: 添加一行字符集: 然后重启服务,就OK了

  4. 【Jetty】Jetty 的工作原理以及与 Tomcat 的比较

    Jetty 应该是目前最活跃也是很有前景的一个 Servlet 引擎.本文将介绍 Jetty 基本架构与基本的工作原理:您将了解到 Jetty 的基本体系结构:Jetty 的启动过程:Jetty 如何 ...

  5. TinyXML2 的使用

    TinyXML是一个开源的解析XML的解析库,能够用于C++,能够在Windows或Linux中编译.这个解析库的模型通过解析XML文件,然后在内存中生成DOM模型,从而让我们很方便的遍历这棵XML树 ...

  6. 11款CSS3动画工具的开发

    本文展示了11个最好的和最令人惊异的CSS3动画工具,将为开发者是非常有帮助的.CSS3有设计师和开发人员之间的良好的声誉.它是在这里帮助他们创造惊人的结果. 有了这些动画工具,你可以创造一个轻松自由 ...

  7. Mysql字符串字段中是否包含某个字符串,用 find_in_set

    有这样一个需求,在Mysql数据库字符串字段(权限)中,有范围在 1 到 N 之间代表不同权限的值,分别被‘,’分开,现在要取出具有某权限的所有成员列表. 创建表:   1 CREATE TABLE ...

  8. 【GMT43智能液晶模块】例程九:RTC实验——时钟显示

    实验原理: STM32的实时时钟(RTC)是一个独立的定时器,有一组连续计数的 计数器,通过软件来对其进行相关的配置,可以提供时钟功能,通过修改计 数器的的值,可以调整时钟.最终通过emWin在显示屏 ...

  9. 教你一招:解决Windows 开机弹出AotuIt ERROR 错误

    AutoIt是个脚本语言,常被用于自动化安装.网络上有些系统镜像里含有AutoIt脚本,用于系统的自动配置.出现这种问题往往有两种可能的原因: 1)做系统的时候没搞好.这种情况就需要换一个镜像文件. ...

  10. Envoy 代替nginx https://www.jianshu.com/p/0a1f67b42fdb

    官方文档: https://www.envoyproxy.io/docs1.6.0版官方文档: https://www.envoyproxy.io/docs/envoy/v1.6.0/ 一. 编译和安 ...