双DFS方法就是正dfs扫一遍,然后将边反向dfs扫一遍。《挑战程序设计》上有说明。

双dfs代码:

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <vector> using namespace std;
const int MAXN = 1e4 + ;
vector <int> G[MAXN]; //图的邻接表
vector <int> RG[MAXN]; //图的反向邻接表
vector <int> vs; //后序遍历的顶点顺序表
bool ok[MAXN]; //访问标记
int node[MAXN]; //所属强连通分量的序号
//第一次dfs
void dfs(int u) {
ok[u] = true;
for(int i = ; i < G[u].size() ; i++) {
if(!ok[G[u][i]])
dfs(G[u][i]);
}
vs.push_back(u);
}
//第二次dfs
void rdfs(int u , int k) {
node[u] = k;
ok[u] = true;
for(int i = ; i < RG[u].size() ; i++) {
if(!ok[RG[u][i]])
rdfs(RG[u][i] , k);
}
} int main()
{
int n , m , u , v;
while(~scanf("%d %d" , &n , &m) && (n || m)) {
for(int i = ; i <= n ; i++) {
G[i].clear();
RG[i].clear();
ok[i] = false;
vs.clear();
}
for(int i = ; i < m ; i++) {
scanf("%d %d" , &u , &v);
G[u].push_back(v);
RG[v].push_back(u);
}
//第一次dfs 选取任意的顶点作为起点遍历 后序遍历 越接近图尾部(叶子)的顶点顺序越小
for(int i = ; i <= n ; i++) {
if(!ok[i])
dfs(i);
}
memset(ok , false , sizeof(ok));
int k = ;
//第二次dfs 将边反向遍历 以标记最大的顶点作为起点遍历 这样便可以给强连通分量标号
for(int i = vs.size() - ; i >= ; i--) {
if(!ok[vs[i]])
rdfs(vs[i] , ++k);
}
if(k > ) {
printf("No\n");
}
else {
printf("Yes\n");
}
}
}

tarjan代码虽然比双dfs多,理解也稍微复杂,但是用处比较多,像求LCA 桥 scc之类的问题。

推荐一个学scc的blog,讲的很好。 https://www.byvoid.com/blog/tag/%E5%9C%96%E8%AB%96

代码如下:

 //以hdu1269为例
//强连通分量 tarjan算法
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
const int MAXN = 1e4 + ;
vector <int> G[MAXN]; //临接表
bool instack[MAXN]; //i是否还在在栈里
int sccnum , index; //连通分量数 和时间顺序
int top , st[MAXN]; //存储i的模拟栈
int block[MAXN]; //i所属的连通分量
int low[MAXN] , dfn[MAXN]; //i能最早访问到的点 和时间戳 void tarjan(int u) {
st[++top] = u;
instack[u] = true;
low[u] = dfn[u] = ++index;
for(int i = ; i < G[u].size() ; i++) {
int v = G[u][i];
if(!dfn[v]) { //v点没访问过
tarjan(v);
if(low[v] < low[u]) { //回溯上来 low[v]表示的时间戳(连通分量的根) u和v在一个连通分量里
low[u] = low[v];
}
}
else if(instack[v]) { //v还在栈里 说明u和v在一个连通分量(形成环路) v相当于连通分量的一个根
low[u] = min(low[u] , dfn[v]);
}
}
int v;
if(dfn[u] == low[u]) { //是连通分量的根
sccnum++;
do {
v = st[top--];
block[v] = sccnum;
instack[v] = false;
}while(v != u); //连通分量的所有的点
}
} void init(int n) {
for(int i = ; i <= n ; i++) {
G[i].clear();
instack[i] = false;
dfn[i] = ;
}
sccnum = index = top = ;
} int main()
{
int n , m , u , v;
while(~scanf("%d %d" , &n , &m) && (n || m)) {
init(n);
for(int i = ; i < m ; i++) {
scanf("%d %d" , &u , &v);
G[u].push_back(v);
}
for(int i = ; i <= n ; i++) {
if(!dfn[i]) {
tarjan(i);
}
}
if(sccnum > ) {
cout << "No\n";
}
else {
cout << "Yes\n";
}
}
}

强连通分量(tarjan求强连通分量)的更多相关文章

  1. UESTC 901 方老师抢银行 --Tarjan求强连通分量

    思路:如果出现了一个强连通分量,那么走到这个点时一定会在强连通分量里的点全部走一遍,这样才能更大.所以我们首先用Tarjan跑一遍求出所有强连通分量,然后将强连通分量缩成点(用到栈)然后就变成了一个D ...

  2. tarjan求强连通分量+缩点+割点以及一些证明

    “tarjan陪伴强联通分量 生成树完成后思路才闪光 欧拉跑过的七桥古塘 让你 心驰神往”----<膜你抄>   自从听完这首歌,我就对tarjan开始心驰神往了,不过由于之前水平不足,一 ...

  3. Tarjan求强连通分量,缩点,割点

    Tarjan算法是由美国著名计算机专家发明的,其主要特点就是可以求强连通分量和缩点·割点. 而强联通分量便是在一个图中如果有一个子图,且这个子图中所有的点都可以相互到达,这个子图便是一个强连通分量,并 ...

  4. tarjan求强连通分量+缩点+割点/割桥(点双/边双)以及一些证明

    “tarjan陪伴强联通分量 生成树完成后思路才闪光 欧拉跑过的七桥古塘 让你 心驰神往”----<膜你抄>   自从听完这首歌,我就对tarjan开始心驰神往了,不过由于之前水平不足,一 ...

  5. HDU 1827 Summer Holiday(tarjan求强连通分量+缩点构成新图+统计入度+一点贪心思)经典缩点入门题

    Summer Holiday Time Limit: 10000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)T ...

  6. CCF 高速公路 tarjan求强连通分量

    问题描述 某国有n个城市,为了使得城市间的交通更便利,该国国王打算在城市之间修一些高速公路,由于经费限制,国王打算第一阶段先在部分城市之间修一些单向的高速公路. 现在,大臣们帮国王拟了一个修高速公路的 ...

  7. UVALive 4262——Trip Planning——————【Tarjan 求强连通分量个数】

    Road Networks Time Limit:3000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu Submit Stat ...

  8. tarjan求强连通分量(模板)

    https://www.luogu.org/problem/P2341 #include<cstdio> #include<cstring> #include<algor ...

  9. Tarjan求强连通分量、求桥和割点模板

    Tarjan 求强连通分量模板.参考博客 #include<stdio.h> #include<stack> #include<algorithm> using n ...

随机推荐

  1. 函数xdes_get_offset

    /********************************************************************//** Returns page offset of the ...

  2. 高斯消元与xor方程组

    ;i<=n;i++) { ;j<=n;j++) if(a[j]>a[i]) swap(a[i],a[j]); if(!a[i]) break; ;j>=;j--) ) { ;k ...

  3. 最受Web前端开发者欢迎的五大开发工具

    工其事,必利于器.好的开发工具毋容置疑会帮助Web前端开发者事半功倍,51CTO在上期主办的技术沙龙<大型网站PHP开发之道> 对现场的百余位Web开发者做了问卷调查,后经51CTO调研小 ...

  4. 通过CSS禁止Chrome自动为输入框添加橘黄色边框,修改/禁止 chrome input边框颜色,

    1   /*Chrome浏览器 点击input 黄色边框 禁用*/ .NoOutLine:focus{outline: none} <asp:TextBox ID="txtTeleph ...

  5. AngularJS promise()

    实例说明一 <!DOCTYPE html> <html ng-app="my-app"> <head> <meta charset=&qu ...

  6. apache开源项目 -- tomee

    Apache TomEE,发音是“Tommy”,是一个经Apache.JavaEE6.Web框架认证的适配器,其在Tomcat服务器中是最强大的.Apache TomEE是由香草项目(简化常见编程任务 ...

  7. Swift入门篇-基本类型(1)

    博主语文一直都不好(如有什么错别字,请您在下评论)望您谅解,没有上过什么学的 今天遇到了一个很烦的事情是,早上10点钟打开电脑,一直都进入系统(我的系统  mac OS X Yosemite 10.1 ...

  8. Chrome 实用调试技巧

    Chrome 实用调试技巧 2016-07-23 如今Chrome浏览器无疑是最受前端青睐的工具,原因除了界面简洁.大量的应用插件,良好的代码规范支持.强大的V8解释器之外,还因为Chrome开发者工 ...

  9. SQL之50个常用的SQL语句

    50个常用的sql语句 Student(S#,Sname,Sage,Ssex) 学生表 Course(C#,Cname,T#) 课程表 SC(S#,C#,score) 成绩表 Teacher(T#,T ...

  10. storm入门教程 第四章 消息的可靠处理【转】

    4.1 简介 storm可以确保spout发送出来的每个消息都会被完整的处理.本章将会描述storm体系是如何达到这个目标的,并将会详述开发者应该如何使用storm的这些机制来实现数据的可靠处理. 4 ...