PS:在贴出代码之前,我得说明内容来源——哈尔滨工业大学出版的《图论及应用》。虽然有一些错误的地方,但是不得不说是初学者该用的书。

  从效率的角度来说,Kosaraju <Tarjan<Garbow。一般网上有前两种的代码和分析。Garbow算法是Tarjan的另一种实现,但是Garbow效率更高。

  不过从复杂度来说,三种算法的时间(空间)复杂度都是O(m +n)。

  模版的调用方式很简单,初始化,建图,调用Tarjan(n)或者Kosaraju(n)或者 Garbow(n), scc就是强连通分量的个数。

(1)Kosaraju
//Kosaraju
const int N =, M=;
struct node
{
int to, next;
}edge[M],edge2[M]; //edge是逆图,edge2是原图
int dfn[N], head[N], head2[N], belg[N], num[N];
//dfn时间戳
//belg记录每个点属于哪个连通分量,num记录强连通分量点的个数
bool vis[N];
int cnt,cnt1,scc,tot,tot1;
void dfs1(int u)
{
vis[u]=;
for(int k=head2[u];k!=-;k=edge2[k].next)
if(!vis[edge2[k].to]) dfs1(edge2[k].to);
dfn[++cnt1]=u;
}
void dfs2(int u)
{
vis[u]=;
cnt++;
belg[u]=scc;
for(int k=head[u];k!=-;k=edge[k].next)
if(!vis[edge[k].to]) dfs2(edge[k].to);
}
void Kosaraju(int n)
{
memset(dfn,,sizeof(dfn));
memset(vis,,sizeof(vis));
cnt1=scc=;
for(int i=;i<=n;i++)
if(!vis[i]) dfs1(i);
memset(vis,,sizeof(vis));
for(int i=cnt1;i>;i--)
if(!vis[dfn[i]])
{
cnt=;
++scc;
dfs2(dfn[i]);
num[scc] = cnt;
}
}
void init()
{
tot=tot1=;
memset(head,-,sizeof(head));
memset(head2,-,sizeof(head2));
memset(num,,sizeof(num));
}
void addedge(int i,int j)
{
edge2[tot1].to=j; edge2[tot1].next=head2[i];head2[i]=tot1++;
edge[tot].to=i; edge[tot].next=head[j];head[j]=tot++;
}
(2)Tarjan
//Tarjan
const int N =, M=;
struct node
{
int to, next;
}edge[M];
int head[N], low[N], dfn[N], sta[N], belg[N], num[N];
bool vis[N];
int scc,index,top, tot;
void tarbfs(int u)
{
int i,j,k,v;
low[u]=dfn[u]=++index;
sta[top++]=u;
vis[u]=;
for(i=head[u];i!=-;i=edge[i].next)
{
v=edge[i].to;
if(!dfn[v])
{
tarbfs(v);
if(low[u]>low[v]) low[u]=low[v];
}
else if(vis[v]&&low[u]>dfn[v]) low[u]=dfn[v];
}
if(dfn[u]==low[u])
{
scc++;
do
{
v=sta[--top];
vis[v]=;
belg[v]=scc;
num[scc]++;
}
while(v!=u) ;
}
}
void Tarjan(int n)
{
memset(vis,,sizeof(vis));
memset(dfn,,sizeof(dfn));
memset(num,,sizeof(num));
memset(low,,sizeof(low));
index=scc=top=;
for(int i=;i<=n;i++)
if(!dfn[i]) tarbfs(i);
}
void init()
{
tot=;
memset(head,-,sizeof(head));
}
void addedge(int i,int j)
{
edge[tot].to=j; edge[tot].next=head[i];head[i]=tot++;
}
(3)Garbow
//Garbow
const int N =, M=;
struct node
{
int to, next;;
}edge[M];
int stk[N],stk2[N],head[N],low[N],belg[N];
int cn,cm,tot,scc,lay;
int Garbowbfs(int cur,int lay)
{
stk[++cn]=cur; stk2[++cm]=cur;
low[cur]=++lay;
for(int i=head[cur];i!=-;i=edge[i].next)
{
int v=edge[i].to;
if(!low[v]) Garbowbfs(v,lay);
else if(!belg[v])
while(low[stk2[cm]]>low[v]) cm--;
}
if(stk2[cm]==cur)
{
cm--;
scc++;
do
belg[stk[cn]]=scc;
while(stk[cn--]!=cur) ;
}
return ;
} void Garbow(int n)
{
scc=lay=;
memset(belg,,sizeof(belg));
memset(low,,sizeof(low));
for(int i=;i<n;i++)
if(!low[i]) Garbowbfs(i,lay);
}
void init()
{
memset(head,-,sizeof(-));
}
void addedge(int i,int j)
{
edge[tot].to=j; edge[tot].next=head[i];head[i]=tot++;
}

强连通分量的模版 Kosaraju+Tarjan+Garbow的更多相关文章

  1. 算法数据结构 | 三个步骤完成强连通分量分解的Kosaraju算法

    强连通分量分解的Kosaraju算法 今天是算法数据结构专题的第35篇文章,我们来聊聊图论当中的强连通分量分解的Tarjan算法. Kosaraju算法一看这个名字很奇怪就可以猜到它也是一个根据人名起 ...

  2. HDU 1269 迷宫城堡(判断有向图强连通分量的个数,tarjan算法)

    迷宫城堡 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submis ...

  3. POJ2186 Popular Cows 【强连通分量】+【Kosaraju】+【Tarjan】+【Garbow】

    Popular Cows Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 23445   Accepted: 9605 Des ...

  4. (转)求有向图的强连通分量个数(kosaraju算法)

    有向图的连通分量的求解思路 kosaraju算法 逛了很多博客,感觉都很难懂,终于找到一篇能看懂的,摘要记录一下 原博客https://www.cnblogs.com/nullzx/p/6437926 ...

  5. 有向图的强连通分量的求解算法Tarjan

    Tarjan算法 Tarjan算法是基于dfs算法,每一个强连通分量为搜索树中的一颗子树.搜索时,把当前搜索树中的未处理的结点加入一个栈中,回溯时可以判断栈顶到栈中的结点是不是在同一个强连通分量中.当 ...

  6. 求有向图的强连通分量个数 之 Kosaraju算法

    代码: #include<cstdio> #include<cstring> #include<iostream> using namespace std; ][] ...

  7. Tarjan算法分解强连通分量(附详细参考文章)

    Tarjan算法分解强连通分量 算法思路: 算法通过dfs遍历整个连通分量,并在遍历过程中给每个点打上两个记号:一个是时间戳,即首次访问到节点i的时刻,另一个是节点u的某一个祖先被访问的最早时刻. 时 ...

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

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

  9. [Uva247][Tarjan求强连通分量][Calling Circles]

    题目大意: 例如:A跟B打电话,B跟C打电话,C跟A打电话..D跟E打电话,E跟D不打电话.则A,B,C属于同一个电话圈,D,E分别属于一个电话圈,问有多少个电话圈. 分析 就是裸的求强连通分量,直接 ...

随机推荐

  1. window path 的基本配置

    %JAVA_HOME%\bin;%SystemRoot%\system32;%SystemRoot%;%SystemRoot%\System32\Wbem;%SYSTEMROOT%\System32\ ...

  2. Python字符串格式化--formate()的应用

    1.简单运用字符串类型格式化采用format()方法,基本使用格式是:转自 <模板字符串>.format(<逗号分隔的参数>) 调用format()方法后会返回一个新的字符串, ...

  3. Dart 调用C语言混合编程

    Dart 调用C语言本篇博客研究Dart语言如何调用C语言代码混合编程,最后我们实现一个简单示例,在C语言中编写简单加解密函数,使用dart调用并传入字符串,返回加密结果,调用解密函数,恢复字符串内容 ...

  4. Java-Class-Test:Test-1

    ylbtech-Java-Class-Test:Test-1 1.返回顶部 1.1. package com.ylbtech.api; import com.y;btech.WxApiApplicat ...

  5. https证书安装无效的主要原因

    https证书的作用是为了确认服务端身份,但网络上充满了无效的证书,浏览器对使用无效证书的访问,给出危险.不安全警告,将是否选择继续访问由用户选择,而大多数用户是无法区分这是配置还是真的存在安全问题. ...

  6. Redis启动出错 noauth authentication required.

    输入认证过的密码即可. 在命令行中运行: auth password

  7. base64模块 简单了解

    base64,字符串文本编码解码,方便数据进行传输 import base64 '''编码解码''' st = 'ni hao'.encode('utf8') result = base64.b64e ...

  8. 2018ICPC南京

    可能上一次秦皇岛拿了银,有了偶像包袱? 打的时候感觉状态不是很好. 第一题,让你每次将连续一段区间的石头都拿掉.. 然后让你做个博弈. 橘子一顿分析,认为k+1的倍数都是输. 这时,我们以及默认i+1 ...

  9. 【ACM】hdu_2020_绝对值排序_201308050929

    绝对值排序 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submi ...

  10. 混乱的URL编码-C#-JavaScript

    文章地址 前后端传值的时候,有时候总是遇到乱码不知道怎么解决,这个还是要分析下各个语言的编码格式 JavaScript中编码有三种方法:escape.encodeURI.encodeURICompon ...