强连通分量(tarjan求强连通分量)
双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求强连通分量)的更多相关文章
- UESTC 901 方老师抢银行 --Tarjan求强连通分量
思路:如果出现了一个强连通分量,那么走到这个点时一定会在强连通分量里的点全部走一遍,这样才能更大.所以我们首先用Tarjan跑一遍求出所有强连通分量,然后将强连通分量缩成点(用到栈)然后就变成了一个D ...
- tarjan求强连通分量+缩点+割点以及一些证明
“tarjan陪伴强联通分量 生成树完成后思路才闪光 欧拉跑过的七桥古塘 让你 心驰神往”----<膜你抄> 自从听完这首歌,我就对tarjan开始心驰神往了,不过由于之前水平不足,一 ...
- Tarjan求强连通分量,缩点,割点
Tarjan算法是由美国著名计算机专家发明的,其主要特点就是可以求强连通分量和缩点·割点. 而强联通分量便是在一个图中如果有一个子图,且这个子图中所有的点都可以相互到达,这个子图便是一个强连通分量,并 ...
- tarjan求强连通分量+缩点+割点/割桥(点双/边双)以及一些证明
“tarjan陪伴强联通分量 生成树完成后思路才闪光 欧拉跑过的七桥古塘 让你 心驰神往”----<膜你抄> 自从听完这首歌,我就对tarjan开始心驰神往了,不过由于之前水平不足,一 ...
- HDU 1827 Summer Holiday(tarjan求强连通分量+缩点构成新图+统计入度+一点贪心思)经典缩点入门题
Summer Holiday Time Limit: 10000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)T ...
- CCF 高速公路 tarjan求强连通分量
问题描述 某国有n个城市,为了使得城市间的交通更便利,该国国王打算在城市之间修一些高速公路,由于经费限制,国王打算第一阶段先在部分城市之间修一些单向的高速公路. 现在,大臣们帮国王拟了一个修高速公路的 ...
- UVALive 4262——Trip Planning——————【Tarjan 求强连通分量个数】
Road Networks Time Limit:3000MS Memory Limit:0KB 64bit IO Format:%lld & %llu Submit Stat ...
- tarjan求强连通分量(模板)
https://www.luogu.org/problem/P2341 #include<cstdio> #include<cstring> #include<algor ...
- Tarjan求强连通分量、求桥和割点模板
Tarjan 求强连通分量模板.参考博客 #include<stdio.h> #include<stack> #include<algorithm> using n ...
随机推荐
- 418. Sentence Screen Fitting
首先想到的是直接做,然后TLE. public class Solution { public int wordsTyping(String[] sentence, int rows, int col ...
- hdu 4901 The Romantic Hero (dp)
题目链接 题意:给一个数组a,从中选择一些元素,构成两个数组s, t,使s数组里的所有元素异或 等于 t数组里的所有元素 位于,求有多少种构成方式.要求s数组里 的所有的元素的下标 小于 t数组里的所 ...
- Codeforces 383A - Milking cows
原题地址:http://codeforces.com/problemset/problem/383/A 题目大意:有 n 头奶牛,全部看着左边或者右边,现在开始给奶牛挤奶,给一头奶牛挤奶时,所有能看到 ...
- ASP.NET Redis 开发(转载)
Redis简介 Redis是一个开源的,使用C语言编写,面向“键/值”对类型数据的分布式NoSQL数据库系统,特点是高性能,持久存储,适应高并发的应用场景.Redis纯粹为应用而产生,它是一个高性能的 ...
- js 跨域的问题 (同一个主域名不同的二级域名下的跨域问题) 解决 WdatePicker.js my97日期选择控件
例如域名是 a.xx.com 和 b.xx.com 如果一个页面中引入多个iframe,要想能够操作所有iframe,必须都得设置相同domain. 如果iframe的时候 a包含b 为 ...
- 《C++ Primer 4th》读书笔记 第12章-类
原创文章,转载请注明出处:http://www.cnblogs.com/DayByDay/p/3936473.html
- IOS 五星评分控件
程序中需要打分的功能,在网上找了几个,都不是很满意.下面是实现出的效果.可以点击,可以拖动. 使用方法:初始化控件. TQStarRatingView *starRatingView = [[TQSt ...
- C# 中LinkLabel的简单使用
界面中加入一个LinkLabel控件
- Oracle归档方式设置
一 设置为归档方式Sql代码 sql> archive log list; #查看是不是归档方式 sql> alter system set log_archive_start=true ...
- duilib中控件拖拽功能的实现方法(附源码)
转载请说明原出处,谢谢~~:http://blog.csdn.net/zhuhongshu/article/details/41144283 duilib库中原本没有显示的对控件增加拖拽的功能,而实际 ...