首页 > 其他分享 >Tarjan强连通分量详解

Tarjan强连通分量详解

时间:2023-10-08 19:45:37浏览次数:44  
标签:Tarjan int 结点 连通 dfn low 详解 分量

1、简介:

在阅读下列内容之前,请务必了解 图论相关概念 中的基础部分。

强连通的定义是:有向图 G 强连通是指,G 中任意两个结点连通。

强连通分量(Strongly Connected Components,SCC)的定义是:极大的强连通子图。

这里要介绍的是如何来求强连通分量。

2、引入:

在介绍该算法之前,先来了解 DFS 生成树,我们以下面的有向图为例:

DFS生成树

 

3、算法思想:

求强连通分量就相当于求(或类似于环可以一遍又一遍无限走下去,切走不出这个环)的个数。

其他人博客上说什么:树边(tree edge),横叉边(cross edge),反祖边(back edge),前向边(forward edge),这些太复杂了,对像我一样的蒟蒻不友好以下是一段简洁的解释。

先说算法步骤:

1、我们要对一张图(有向图)进行遍历。

       记录:dfn[x]:   存x点的时间戳(是第几个遍历这个点的),(相当于记录了遍历的顺序);

                  low[x]:   存x点最早能访问到的时间戳。

2、思考:若dfn[x]=low[x],就说明x点无论怎么走,都无法到达时间戳更靠前的点,证明x点是一个环的开始(环顶)。

3、将遍历到的点依次入栈,当判断到环顶时,栈中的点就是一个强连通分量。

4、详细步骤:

  • 一个结点的子树内结点的 dfn 都大于该结点的 dfn。
  • 从根开始的一条路径上的 dfn 严格递增,low 严格非降。

按照深度优先搜索算法搜索的次序对图中所有的结点进行搜索,维护每个结点的 dfn 与 low 变量,且让搜索到的结点入栈。每当找到一个强连通元素,就按照该元素包含结点数目让栈中元素出栈。在搜索过程中,对于结点  和与其相邻的结点  不是  的父节点)考虑 3 种情况:

  1.  v未被访问:继续对 v 进行深度搜索。在回溯过程中,用 low[v] 更新 。因为存在从 u 到 v 的直接路径,所以说 v 能够回溯到的已经在栈中的结点,u 也一定能够回溯到。
  2.  v被访问过,已经在栈中:根据 low 值的定义,用 dfn[v] 或low[v] 更新 low[u] 
  3.  v被访问过,已不在栈中:说明v已搜索完毕,其所在连通分量已被处理,所以不用对其做操作。

5、例题:(洛谷 P2863 [USACO06JAN] The Cow Prom S)

        

//洛谷 P2863 [USACO06JAN] The Cow Prom S 
#include<bits/stdc++.h>
using namespace std;
const int N=2e4+2,M=5e4+2;
int n,m,dfn[N],low[N],first[N],stk[N],siz[N],top=0,tot=0,cnt=0,ans=0;
bool in[N];
struct node{int v,ne;}e[M];
void add(int u,int v){
    e[++tot]={v,first[u]};
    first[u]=tot;
}
void tarjan(int u){       //tarjan算法求强连通分量
    dfn[u]=low[u]=++tot;
    in[u]=1;       //表示u点在栈中 
    stk[++top]=u;  //将u记入栈中 
    for(int i=first[u];i;i=e[i].ne){
        int v=e[i].v;
        if(!dfn[v]){
            tarjan(v);
            low[u]=min(low[u],low[v]);  //更新low[u]值的意义是让u点不提前出栈 
        }
        else if(in[v]) low[u]=min(low[u],low[v]);
    }
    if(low[u]==dfn[u]){
        int y;
        ++cnt;
        do{
            y=stk[top--];in[y]=0;
            siz[cnt]++;
        }while(u!=y);
    }
}
int main(){
    scanf("%d%d",&n,&m);
    int u,v;
    for(int i=1;i<=m;++i){
        scanf("%d%d",&u,&v);
        add(u,v);          //建单向边 
    }
    for(int i=1;i<=n;++i) if(!dfn[i]) tarjan(i);  //图有可能不连通,存在几个分开的图 
    for(int i=1;i<=cnt;++i) if(siz[i]>1) ans++;   //siz[]记录每一个强连通分量的大小 
    printf("%d",ans);
    return 0;
}

 

标签:Tarjan,int,结点,连通,dfn,low,详解,分量
From: https://www.cnblogs.com/wenyutao1/p/17749979.html

相关文章

  • 密码协议学习笔记(8.15):知识证据详解
    在开始前,先回顾以下的知识点:离散对数问题(DiscretelogarithmProblem,DLP)难解性猜想:给定以大素数$p$为阶的循环群$G$,$g,h\inG$是两个生成元(在素数阶群上等价于非恒等元),求解$t$,使得$h^t=g$在计算上是不可行的.Diffie-Hellman的计算难解性(ComputationalDiffie-Hellm......
  • JRTPLIB详解
    简介RTP是目前解决流媒体实时传输问题的最好办法,如果需要在Linux平台上进行实时流媒体编程,可以考虑使用一些开放源代码的RTP库,如LIBRTP、JRTPLIB等。JRTPLIB是一个面向对象的RTP库,它完全遵循RFC1889设计,在很多场合下是一个非常不错的选择,下面就以JRTPLIB为例,讲述如何在Linux......
  • MYSQL中 find_in_set() 函数用法详解(匹配部门id或父id为100的数据)
    https://blog.csdn.net/carefree31441/article/details/119563685   ......
  • odoo14 生成PDF报表详解
    1.新建report目录-新建报表xml文件material_storage_pdf.xml2. 定义xml文件报表参数参数ir.actions.report报表属性name:打印动作按钮下的报表名字model:你的报表相关的模型,也就是说是你下载pdf中,pdf中数据的来源report_type:PDF报表的qweb-pdf或HTML的qweb-html,就是下载的报......
  • JS 全屏和退出全屏--requestFullScreen详解及兼容代码
    浏览器全屏实现方式1.利用h5的 requestFullScreen2.摁F11实现全屏效果requestFullscreen全屏具体实现1.进入全屏   functionfull(ele){ if(ele.requestFullscreen){ ele.requestFullscreen(); }elseif(ele.mozRequestFullScr......
  • redis服务配置文件详解
    bind0.0.0.0#监听地址,可以用空格隔开后多个监听IPprotected-modeyes#redis3.2之后加入的新特性,在没有设置bindIP和密码的时候,redis只允许访问127.0.0.1:6379,可以远程连接,但当访问将提示警告信息并拒绝远程访问port6379#监听端口,默认6379/tcptcp-backlog511#三次......
  • RDB、AOF详解及优缺点总结
    1.RDB模式优缺点1.1.RDB模式优点1.1.1.RDB快照保存了某个时间点的数据,可以通过脚本执行redis指令bgsave(非阻塞,后台执行)或者save(会阻塞写操作,不推荐)命令自定义时间点备份,可以保留多个备份,当出现问题可以恢复到不同时间点的版本,很适合备份,并且此文件格式也支持有不少第三......
  • 详解PHP反射API
    反射API的部分类使用反射API这些类,可以获得在运行时访问对象、函数和脚本中的扩展的信息。通过这些信息可以用来分析类或者构建框架。类描    述Reflection为类的摘要信息提供静态函数export()ReflectionClass类信息和工具ReflectionMethod类方法信......
  • 若依系统将Mybatis升级为Mybatis-Plus详解
    1.找到ruoyi-framework/...../config/MybatisConfig,将其sqlSessionFactory(DataSourcedataSource)注释2.找到整个项目的pom文件,添加Mybatis-plus版本号3.找到ruoyi-common的pom文件,添加依赖4.找到ruoyi-admin/../resources/application.yml文件,添加plus的配置文件简简单......
  • c#组合模式详解
    基础介绍:  组合模式用于表示部分-整体的层次结构。适用于希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象的情况。  顾名思义,什么叫部分-整体,比如常见的前端UI,一个DIV标签中可以存在多个A标签、P标签、DIV标签等等。  相较于DIV这个容器整体......