强连通分量与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)的算法. 首先我们 ...
随机推荐
- git cherry-pick 总结
git cherry-pick cherry-pick : 精心挑选,挑选一个我们需要的 commit 进行操作.它可以用于将在其他分支上的 commit 移植到当前的分支. 用法: // 复制com ...
- 创建x11vnc系统进程
〇.前言 为方便使用vnc,所以寻找到一个比较好用的vnc服务端那就是x11vnc,索性就创建了一个系统进程 一.环境 系统:银河麒麟v4-sp2-server 软件:x11vnc[linux下].V ...
- 阿里云Centos7部署私人CSGO服务器
大四毕业生,论文和答辩分别以1.8%的重复率和只答不辨的态度双双过关.现在就是在家等着学校发毕业证了.顺带学学驾驶...可是我这么一个喜欢折腾的人,怎么能够让自己接受这么无聊的咸鱼时光呢?因为这个寒假 ...
- HTTP和Servlet快速入门
目录 1.HTTP 1.1 请求数据格式 1.2 相应数据格式 2.Servlet 3.Servlert的xml配置 1.HTTP 1.1 请求数据格式 请求行:请求数据的第一行 包含三个内容,按顺序 ...
- WSUS无法发现客户端
这几天遇到一个问题,刚装好的WSUS服务器同步完补丁后,打算上线使用.挑了几个客户端,使用注册表配置了WSUS,但是迟迟无法在控制台上看到这些客户端.由于部分客户端不在域中,无法使用组策略配置,就写了 ...
- UEC++ 接口
词义广泛,用来陈述功能,选项,与其他程序结构进行沟通的方式.接口抽象出了交互结构,提供了两个未知逻辑交互的便捷性.对于编程中,如何更好的设计低耦合程序起到了至关重要的作用.设计者可以在互不关心的情况下 ...
- ELK日志报警插件ElastAlert并配置钉钉报警
文章转载自:https://www.cnblogs.com/uglyliu/p/13118386.html ELK日志报警插件ElastAlert 它通过将Elasticsearch与两种类型的组件( ...
- NetworkPolicy网络策略以及举例说明
网络策略(NetworkPolicy)是一种关于pod间及pod与其他网络端点间所允许的通信规则的规范.NetworkPolicy 资源使用标签选择pod,并定义选定pod所允许的通信规则. 前提 网 ...
- 12. Fluentd部署:多Workers进程模式
介绍如何使用Fluentd的多worker模式处理高访问量的日志事件.此模式会运行多个worker进程以最大利用多核CPU. 原理 默认情况下,一个Fluentd实例会运行一个监控进程和一个工作进程. ...
- HDU4991 Ordered Subsequence (树状数组优化DP)
dp[i][j]表示以a[i]结尾的长度为j的上升子序列个数. 方程:dp[i][j]=sum(dp[k][j-1]),a[k]<a[i],1<=k<i. 求解目标:sum(dp[k ...