模板题:B3609 [图论与代数结构 701] 强连通分量

题目描述

给定一张 n 个点 m 条边的有向图,求出其所有的强连通分量。

注意,本题可能存在重边和自环。

输入格式

第一行两个正整数 n , m ,表示图的点数和边数。

接下来 m 行,每行两个正整数 u 和 v 表示一条边。

输出格式

第一行一个整数表示这张图的强连通分量数目。

接下来每行输出一个强连通分量。第一行输出 1 号点所在强连通分量,第二行输出 2 号点所在强连通分量,若已被输出,则改为输出 3 号点所在强连通分量,以此类推。每个强连通分量按节点编号大小输出。

本题让我们求出强连通分量的数量以及各强连通分量所包含的点。
解决这个问题需要用到taryan算法,下面简要介绍一下该算法的实现。

定义如下概念:
dfn[x]
可以这么理解,对一张图上所有没有遍历过的点进行dfs遍历,dfn[x]就是x点被遍历到的次序。又称dfs序。
low[x]
x所能到达的点中最小的dfs序

在一个强连通分量中,每两个点都是可以互相到达的,那么如果对于点x,low[x]!=dfn[x],说明x可以访问到比它早遍历的点。

若dfn[x]=low[x],说明点x能到达的dfs序最小的点就是x,找到了一个新的强连通分量。

使用栈存储遍历途中经过的点。

代码

#include<bits/stdc++.h>
using namespace std;
const int h=10001;
int head[h],last[h*10],to[h*10],tot=0;
void add_edge(int x,int y){
tot++;
last[tot]=head[x];
head[x]=tot;
to[tot]=y;
} int cnt=0;//标记强连通分量的数量
int timedrop=0;//标记每个点被访问的“时间”
int dfn[h];//dfn存的是这一点被访问的时间
int low[h];//low存的是 这个点可以到达的 “访问时间”最早的点
int belong[h];//存储某个点所属的强连通分量的编号
vector<int>scc[h];
stack<int>s;
bool instack[h];//标记这个点在不在栈内
bool printed[h];//存储该强连通分量是否被输出过
void dfs(int x){
//这是整个程序的核心部分,即如何求强连通分量 timedrop++;
dfn[x]=timedrop;//标记这个点被访问到的时间
low[x]=timedrop;//当前这个点能到达的“访问时间”最早的点只有它自己,以后可能会更新
s.push(x);//将这一点压入栈中
instack[x]=1;
for(int i=head[x];i!=0;i=last[i]){
//这里开始遍历该点可以到达的点,更新这一点的low
int y=to[i];
if(!dfn[y]){//这一点还没有被访问
dfs(y);//那么我们先得到这一点的dfn与low
low[x]=min(low[x],low[y]);//然后用这一点更新当前点
}
else
if(instack[y])//如果这一点在栈中,那这肯定是一个在x之前被访问的点
low[x]=min(low[y],low[x]);
//如果dfn[y]>0且它不在栈中呢?
//那么y已经找到了自己的强连通分量,和x没有关系了
}
if(dfn[x]==low[x]){
//这说明x不能到达在它之前被访问的点
//那么x就是它所在的强连通分量中第一个被访问的点
//并且在这个强连通分量中的所有点已经被压入栈中
//把这些点“取出”即可
cnt++;//新强连通分量内所有的点已经找出
while(s.top()!=x){
int q=s.top();
belong[q]=cnt;
instack[q]=0;
scc[cnt].push_back(q);
s.pop();
}
belong[x]=cnt;
instack[x]=0;
scc[cnt].push_back(x);
s.pop();
} }
int n,m;
int main(){
scanf("%d%d",&n,&m);
//建图
for(int i=1;i<=m;i++){
int a,b;
scanf("%d%d",&a,&b);
add_edge(a,b);
}
for(int i=1;i<=n;i++)
if(!dfn[i])
dfs(i);
printf("%d\n",cnt);
//使用sort对每个强连通分量内的点进行升序排列(以前我也不知道)
for(int i=1;i<=cnt;++i)
sort(scc[i].begin(),scc[i].end());
for(int i=1;i<=n;i++){
int y=belong[i];
if(!printed[y]){
for(int j=0;j<scc[y].size();j++)
printf("%d ",scc[y][j]);
printf("\n");
printed[y]=1;
}
else
continue;
}
return 0;
}

强连通分量与tarjan算法初步运用的更多相关文章

  1. 有向图强连通分量的Tarjan算法

    有向图强连通分量的Tarjan算法 [有向图强连通分量] 在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly connected).如果有向图G的每两个顶点都强连通,称G ...

  2. 强连通分量的Tarjan算法

    资料参考 Tarjan算法寻找有向图的强连通分量 基于强联通的tarjan算法详解 有向图强连通分量的Tarjan算法 处理SCC(强连通分量问题)的Tarjan算法 强连通分量的三种算法分析 Tar ...

  3. 【转】有向图强连通分量的Tarjan算法

    原文地址:https://www.byvoid.com/blog/scc-tarjan/ [有向图强连通分量] 在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly con ...

  4. 算法笔记_144:有向图强连通分量的Tarjan算法(Java)

    目录 1 问题描述 2 解决方案 1 问题描述 引用自百度百科: 如果两个顶点可以相互通达,则称两个顶点强连通(strongly connected).如果有向图G的每两个顶点都强连通,称G是一个强连 ...

  5. 【转载】有向图强连通分量的Tarjan算法

    转载地址:https://www.byvoid.com/blog/scc-tarjan [有向图强连通分量] 在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly conn ...

  6. 有向图强连通分量的Tarjan算法(转)

    [有向图强连通分量] 在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly connected).如果有向图G的每两个顶点都强连通,称G是一个强连通图.非强连通图有向图的极 ...

  7. 『图论』有向图强连通分量的Tarjan算法

    在图论中,一个有向图被成为是强连通的(strongly connected)当且仅当每一对不相同结点u和v间既存在从u到v的路径也存在从v到u的路径.有向图的极大强连通子图(这里指点数极大)被称为强连 ...

  8. 有向图强连通分量的Tarjan算法及模板

    [有向图强连通分量] 在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强联通(strongly connected),如果有向图G的每两个顶点都强联通,称有向图G是一个强联通图.非强联通图有向 ...

  9. 【强连通分量】tarjan算法及kosaraju算法+例题

    阅读前请确保自己知道强连通分量是什么,本文不做赘述. Tarjan算法 一.算法简介 Tarjan算法是一种由Robert Tarjan提出的求有向图强连通分量的时间复杂度为O(n)的算法. 首先我们 ...

随机推荐

  1. identity4 系列————持久化配置篇[五]

    前言 上面已经介绍了3个例子了,并且介绍了如何去使用identity. 但是在前面的例子中,我们使用的都是在内存中操作,那么正式上线可能需要持久到数据库中. 这里值得说明的是,并不一定一定要持久化到数 ...

  2. MQ系列4:NameServer 原理解析

    MQ系列1:消息中间件执行原理 MQ系列2:消息中间件的技术选型 MQ系列3:RocketMQ 架构分析 1 关于NameServer 上一节的 MQ系列3:RocketMQ 架构分析,我们大致介绍了 ...

  3. awk5个使用场景

    awk简介 首先要知道awk的使用场景,需了解awk有哪些优势与短板. 关于个人近期学习awk总结其优势: awk对文本的处理运算效率同比其他工具效率高很多(比shell的for循环高10倍以上,运算 ...

  4. API接口签名校验(C#版)

    我们在提供API服务的时候,为了防止数据传输过程被篡改,通常的做法是对传输的内容进行摘要签名,把签名串同参数一起请求API,API服务接收到请求后以同样的方式生成签名串,然后进行对比,如果签名串不一致 ...

  5. 【读书笔记】C#高级编程 第二章 核心C#

    (一)第一个C#程序 创建一个控制台应用程序,然后输入代码,输入完毕后点击F5 Console.WriteLine();这条语句的意思:把括号内的内容输出到界面上: Console.ReadKey() ...

  6. JavaWeb核心篇(3)——JSP,MVC,三层架构

    JavaWeb核心篇(3)--JSP,MVC,三层架构 在本篇文章中我们会学习到JSP,MVC,三层架构 虽然JSP已经快被时代所淘汰,但是在一些老旧的工作场所还是有在使用,所以了解一下也不为过 至于 ...

  7. Kubernetes 监控:CertManager 自动 HTTPS

    cert-manager 是一种自动执行证书管理的工具,它可以与 Istio Gateway 集成以管理 TLS 证书,当然也可以很方便地和前面我们配置的 ingress-nginx 或者 traef ...

  8. Nginx+lua+openresty精简系列

    1. CentOS系统安装openresty 你可以在你的 CentOS 系统中添加 openresty 仓库,这样就可以便于未来安装或更新我们的软件包(通过 yum update 命令).运行下面的 ...

  9. 17. Fluentd输出插件:out_copy用法详解

    copy即复制,out_copy的作用就是将日志事件复制到多个输出,这样就可以对同一份日志做不同类型的分析处理. out_copy内置于Fluentd,无需单独安装. 示例配置 <match p ...

  10. 8. 使用Fluentd+MongoDB采集Apache日志

    Fluentd+MongoDB,用以实时收集半结构化数据. 背景知识 日志接入Fluentd后,会以json的格式在Fluentd内部进行路由.这就决定了Fluentd处理日志的方式是非常灵活的,它将 ...