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. 安装 Ubuntu 14.04 之后要做的一些事

    转自:  http://www.cnblogs.com/marcowei/p/3841342.html 安装 ubuntu14.04 之后要做的一些事 前言: 用 ubuntu14.04 也有一段时间 ...

  2. sql查询原理

    1.单表查询:根据WHERE条件过滤表中的记录,形成中间表(这个中间表对用户是不可见的):然后根据SELECT的选择列选择相应的列进行返回最终结果. 1)简单的单表查询 SELECT 字段 FROM ...

  3. 利用负margin实现元素居中

    原理就是对当前元素的position设置为absolute并且相对于父元素定位,先设置left:50%;top:50%使当前元素的左上角处于父元素的中心位置,之后再应用负margin特性使其中心位于父 ...

  4. 自己总结的php开发中用到的工具

    需要一个编辑器IDE,推荐用phpstorm. IDE安装完了,还要搞个Xdebug,这个很有用,程序断点跟踪调试就靠他了. phpstom平时使用的时候,编辑界面感觉很枯燥的时候,可以换个主题,换主 ...

  5. Vue CLI 3 中文文档

    翻译文档 文档翻译全貌 前言 之前写了一篇Vue CLI 3.x 版本的简单体验,当时文档还不全,具体的使用方法并不是很清楚,大概是2月7号,收到Vue CLI 3接近Beta版的提示,作者尤雨溪也讲 ...

  6. 继续聊WPF——进度条

    ProgressBar控件与传统WinForm使用方法完全一样,我们只需关注: Minimum——最小值,默认为0: Maximum——最大值,默认为100. Value——当前值.   关键是它的控 ...

  7. HDU 4456 Crowd

    Crowd Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submi ...

  8. 0923如何利用mysqlbinlog日志闪回

    转自 https://github.com/danfengcao/binlog2sql,感谢作者的提供 binlog2sql 从MySQL binlog解析出你要的SQL.根据不同选项,你可以得到原始 ...

  9. PHP扩展开发-测验成功

    原文:http://kimi.it/496.html http://blog.csdn.net/u011957758/article/details/72234075 ---------------- ...

  10. android中常见的内存泄漏和解决的方法

    android中的内存溢出预计大多数人在写代码的时候都出现过,事实上突然认为工作一年和工作三年的差别是什么呢.事实上干的工作或许都一样,产品汪看到的结果也都一样,那差别就是速度和质量了. 写在前面的一 ...