强连通分量与tarjan算法初步运用
模板题: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算法初步运用的更多相关文章
- 有向图强连通分量的Tarjan算法
有向图强连通分量的Tarjan算法 [有向图强连通分量] 在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly connected).如果有向图G的每两个顶点都强连通,称G ...
- 强连通分量的Tarjan算法
资料参考 Tarjan算法寻找有向图的强连通分量 基于强联通的tarjan算法详解 有向图强连通分量的Tarjan算法 处理SCC(强连通分量问题)的Tarjan算法 强连通分量的三种算法分析 Tar ...
- 【转】有向图强连通分量的Tarjan算法
原文地址:https://www.byvoid.com/blog/scc-tarjan/ [有向图强连通分量] 在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly con ...
- 算法笔记_144:有向图强连通分量的Tarjan算法(Java)
目录 1 问题描述 2 解决方案 1 问题描述 引用自百度百科: 如果两个顶点可以相互通达,则称两个顶点强连通(strongly connected).如果有向图G的每两个顶点都强连通,称G是一个强连 ...
- 【转载】有向图强连通分量的Tarjan算法
转载地址:https://www.byvoid.com/blog/scc-tarjan [有向图强连通分量] 在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly conn ...
- 有向图强连通分量的Tarjan算法(转)
[有向图强连通分量] 在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly connected).如果有向图G的每两个顶点都强连通,称G是一个强连通图.非强连通图有向图的极 ...
- 『图论』有向图强连通分量的Tarjan算法
在图论中,一个有向图被成为是强连通的(strongly connected)当且仅当每一对不相同结点u和v间既存在从u到v的路径也存在从v到u的路径.有向图的极大强连通子图(这里指点数极大)被称为强连 ...
- 有向图强连通分量的Tarjan算法及模板
[有向图强连通分量] 在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强联通(strongly connected),如果有向图G的每两个顶点都强联通,称有向图G是一个强联通图.非强联通图有向 ...
- 【强连通分量】tarjan算法及kosaraju算法+例题
阅读前请确保自己知道强连通分量是什么,本文不做赘述. Tarjan算法 一.算法简介 Tarjan算法是一种由Robert Tarjan提出的求有向图强连通分量的时间复杂度为O(n)的算法. 首先我们 ...
随机推荐
- 持久化-Powershell配置文件持久性
持久化-Powershell配置文件持久性 概述 可以使用Powershell配置文件进行持久性和/或特权升级. 执行 获取可以滥用的powershell配置文件,这取决于你拥有的权限. $PROFI ...
- windows优化原神
原神3.0新地图很卡顿? 锐距显卡带不动? 看一下我的配置 英特尔i5-1135G7 内存16GB可以拓展32GB 固态512GB 原神优化前帧率50左右 优化后59-60最差55 展示图原神设置图 ...
- KFS replicator安装(KES-KES)
源端 一.安装前置配置 1.创建安装用户 groupadd flysync useradd flysync -g flysync -G kingbase passwd flysync 2.上传安装文件 ...
- K8S_三种Port区别总结
nodePort: 外部流量访问K8S集群中Service入口的一种方式 比如外部用户要访问k8s集群中的一个Web应用,那么我们可以配置对应service的type=NodePort,nodePor ...
- Windows 2012 R2 iSCSI server
Windows 2012 R2可以充当一台简单的SAN,提供iSCSI方式的连接,供客户端使用.不确定是否有人会这么使用,但至少在做实验的时候我觉得挺方便的.不用再像以前专门安装windows ...
- pod(一):Kubernetes(k8s)创建pod的两种方式
目录 一.系统环境 二.前言 三.pod 四.创建pod 4.1 环境介绍 4.2 使用命令行的方式创建pod 4.2.1 创建最简单的pod 4.2.2 创建pod,指定镜像下载策略 4.2.3 创 ...
- 痞子衡嵌入式:理解i.MXRT中FlexSPI外设lookupTable里配置访问行列混合寻址Memory的参数值
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRT中FlexSPI外设lookupTable里配置访问行列混合寻址Memory的参数值. 关于 FlexSPI 外设的 loo ...
- Python数据科学手册-Numpy入门
通过Python有效导入.存储和操作内存数据的技巧 数据来源:文档.图像.声音.数值等等,将所有的数据简单的看做数字数组 非常有助于 理解和处理数据 不管数据是何种形式,第一步都是 将这些数据转换成 ...
- MySQL 自增字段取值
1 前言 本文来自回答思否网友的一个问题,这个网友新建了一张表,auto_increment_increment设为10,AUTO_INCREMENT主键起始值设为9, 当他插入数据的时候,发现主键值 ...
- shell下cat EOF中变量$处理
在使用cat EOF中出现$变量通常会直接被执行,显示执行的结果.若想保持$变量不变需要使用 \ 符进行注释 [root@localhost ~]# cat >> aa.txt <& ...