强连通分量的模版 Kosaraju+Tarjan+Garbow
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的更多相关文章
- 算法数据结构 | 三个步骤完成强连通分量分解的Kosaraju算法
强连通分量分解的Kosaraju算法 今天是算法数据结构专题的第35篇文章,我们来聊聊图论当中的强连通分量分解的Tarjan算法. Kosaraju算法一看这个名字很奇怪就可以猜到它也是一个根据人名起 ...
- HDU 1269 迷宫城堡(判断有向图强连通分量的个数,tarjan算法)
迷宫城堡 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submis ...
- POJ2186 Popular Cows 【强连通分量】+【Kosaraju】+【Tarjan】+【Garbow】
Popular Cows Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 23445 Accepted: 9605 Des ...
- (转)求有向图的强连通分量个数(kosaraju算法)
有向图的连通分量的求解思路 kosaraju算法 逛了很多博客,感觉都很难懂,终于找到一篇能看懂的,摘要记录一下 原博客https://www.cnblogs.com/nullzx/p/6437926 ...
- 有向图的强连通分量的求解算法Tarjan
Tarjan算法 Tarjan算法是基于dfs算法,每一个强连通分量为搜索树中的一颗子树.搜索时,把当前搜索树中的未处理的结点加入一个栈中,回溯时可以判断栈顶到栈中的结点是不是在同一个强连通分量中.当 ...
- 求有向图的强连通分量个数 之 Kosaraju算法
代码: #include<cstdio> #include<cstring> #include<iostream> using namespace std; ][] ...
- Tarjan算法分解强连通分量(附详细参考文章)
Tarjan算法分解强连通分量 算法思路: 算法通过dfs遍历整个连通分量,并在遍历过程中给每个点打上两个记号:一个是时间戳,即首次访问到节点i的时刻,另一个是节点u的某一个祖先被访问的最早时刻. 时 ...
- UESTC 901 方老师抢银行 --Tarjan求强连通分量
思路:如果出现了一个强连通分量,那么走到这个点时一定会在强连通分量里的点全部走一遍,这样才能更大.所以我们首先用Tarjan跑一遍求出所有强连通分量,然后将强连通分量缩成点(用到栈)然后就变成了一个D ...
- [Uva247][Tarjan求强连通分量][Calling Circles]
题目大意: 例如:A跟B打电话,B跟C打电话,C跟A打电话..D跟E打电话,E跟D不打电话.则A,B,C属于同一个电话圈,D,E分别属于一个电话圈,问有多少个电话圈. 分析 就是裸的求强连通分量,直接 ...
随机推荐
- List分组的两种方式
java8之前List分组 假设有个student类,有id.name.score属性,list集合中存放所有学生信息,现在要根据学生姓名进行分组. public Map<String, Lis ...
- eas之执行sql的方式
客户端: 1. 有返回集合:查询 //查询出DB中所有该字段的值,与其进行比较,若有相同的则报错 String sql="select CFWuliaoCode fr ...
- eas之视图冻结与解冻
// 冻结视图 table.getViewManager().freeze(verticalIndex, horizonIndex); //冻结视图:该方法在table还没显示的时候使用,也就是该方法 ...
- [kernel]----理解kswapd的低水位min_free_kbytes
1. min_free_kbytes 先看官方解释: This is used to force the Linux VM to keep a minimum number of kilobytes ...
- SSH(远程登录)
在linux中SSH服务对应两个配置文件: ssh特点:在传输数据的时候,对文件加密后传输. ssh作用:为远程登录会话和其他网络服务提供安全性协议. ssh小结: 1.SSH是安全的加密协议,用于远 ...
- HTML <area> 对象
<area>对象的属性 属性 描述 W3C alt 设置或返回当浏览器无法显示某个区域时的替换文字. Yes coords 设置或返回图像映射中可点击区域的坐标. Yes hash 设置或 ...
- mysql查询昨天 一周前 一月前 一年前的数据
mysql 昨天 一周前 一月前 一年前的数据 这里主要用到了DATE_SUB, 参考如下 代码如下: SELECT * FROM yh_contentwhere inputtime>DATE_ ...
- 【hihocoder 1475】 数组分拆
[题目链接]:http://hihocoder.com/problemset/problem/1475 [题意] _< [题解] /* 别人的题解 首先对于每个位置预处理数组的前缀和,即s[i] ...
- JAVA反映机制A
以下这个URL讲得不错,可以把概念和用途结合起来, 练练手: http://blog.csdn.net/xiaohai798/article/details/11640427 import java. ...
- [Angular] Angular CDK Intro
1. Installl latest @angular/cli: sudo npm i -g @angular/cli@next The version I used is:6.0.0-rc.10 2 ...