双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. 418. Sentence Screen Fitting

    首先想到的是直接做,然后TLE. public class Solution { public int wordsTyping(String[] sentence, int rows, int col ...

  2. hdu 4901 The Romantic Hero (dp)

    题目链接 题意:给一个数组a,从中选择一些元素,构成两个数组s, t,使s数组里的所有元素异或 等于 t数组里的所有元素 位于,求有多少种构成方式.要求s数组里 的所有的元素的下标 小于 t数组里的所 ...

  3. Codeforces 383A - Milking cows

    原题地址:http://codeforces.com/problemset/problem/383/A 题目大意:有 n 头奶牛,全部看着左边或者右边,现在开始给奶牛挤奶,给一头奶牛挤奶时,所有能看到 ...

  4. ASP.NET Redis 开发(转载)

    Redis简介 Redis是一个开源的,使用C语言编写,面向“键/值”对类型数据的分布式NoSQL数据库系统,特点是高性能,持久存储,适应高并发的应用场景.Redis纯粹为应用而产生,它是一个高性能的 ...

  5. js 跨域的问题 (同一个主域名不同的二级域名下的跨域问题) 解决 WdatePicker.js my97日期选择控件

    例如域名是  a.xx.com  和 b.xx.com    如果一个页面中引入多个iframe,要想能够操作所有iframe,必须都得设置相同domain. 如果iframe的时候  a包含b  为 ...

  6. 《C++ Primer 4th》读书笔记 第12章-类

    原创文章,转载请注明出处:http://www.cnblogs.com/DayByDay/p/3936473.html

  7. IOS 五星评分控件

    程序中需要打分的功能,在网上找了几个,都不是很满意.下面是实现出的效果.可以点击,可以拖动. 使用方法:初始化控件. TQStarRatingView *starRatingView = [[TQSt ...

  8. C# 中LinkLabel的简单使用

    界面中加入一个LinkLabel控件

  9. Oracle归档方式设置

    一 设置为归档方式Sql代码 sql> archive log list; #查看是不是归档方式 sql> alter system set log_archive_start=true ...

  10. duilib中控件拖拽功能的实现方法(附源码)

    转载请说明原出处,谢谢~~:http://blog.csdn.net/zhuhongshu/article/details/41144283 duilib库中原本没有显示的对控件增加拖拽的功能,而实际 ...