强连通分量的模版 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分别属于一个电话圈,问有多少个电话圈. 分析 就是裸的求强连通分量,直接 ...
随机推荐
- BZOJ 4698: Sdoi2008 Sandy的卡片 后缀数组 + RMQ + 查分
题目描述 Sandy和Sue的热衷于收集干脆面中的卡片. 然而,Sue收集卡片是因为卡片上漂亮的人物形象,而Sandy则是为了积攒卡片兑换超炫的人物模型. 每一张卡片都由一些数字进行标记,第i张卡片的 ...
- 设置快捷键用sublime直接打开浏览器
1.安装sidebarenhancements插件 ctrl+shift+p —> Install Package —> 找到SideBarEnhancements 2.配置预览快捷键 / ...
- 基于 Nginx XSendfile + SpringMVC 进行文件下载
转自:http://denger.iteye.com/blog/1014066 基于 Nginx XSendfile + SpringMVC 进行文件下载 PS:经过实际测试,通过 nginx 提供文 ...
- 结构体、枚举、联合(day14)
一个存储区的地址必须是它自身大小的整数倍 (double类型存储区的地址只需要是4的 整数倍) 这个规则叫数据对齐 结构体里面的子存储区通常也需要遵守数据 对齐的规则 数据对齐会造成结构体内部子存储区 ...
- 08.Web服务器-4.Web服务器动态资源请求
1 浏览器请求动态页面过程 2 WSGI 怎么在你刚建立的Web服务器上运行一个Django应用和Flask应用,如何不做任何改变而适应不同的web架构呢? 在以前,选择 Python web 架构会 ...
- PHP统计当前在线用户数实例
HTML 我们在页面上放置一个显示当前在线人数的div#total以及一个用于展示访客地区分布的列表#onlinelist,默认我们在列表中放置一张与加载动画图片,后面我们用jQuery控制当鼠标滑向 ...
- [WordPress]基本操作
编辑文本 文本模式下 more 提取摘要<!--more-->
- [Linux]Apache配置虚拟主机
Apache 配置虚拟主机的方式很多,种类也很多,主要分为两类: 基于名称的虚拟主机 (每个 IP 多个站点) 基于 IP 的虚拟主机 (每个 IP 一个站点) 基于名称的虚拟主机: www.2 ...
- C#编程中,在页面上如何弹出确认删除对话框
对于页面完成一个操作后,弹出一个对话框提示是否“操作成功”.举例如下:Response.Write("<script>alert('删除成功!')</script>& ...
- 网络编程----堵塞、非堵塞和同步、异步IO
我是学渣.但我想进步. 本文是面试我的牛人问我的.你知道什么是堵塞.非堵塞和同步.异步IO么?自觉得是分布式系统程序猿的我居然不知道.学习吧. 首先介绍堵塞IO和非堵塞IO: 堵塞IO:是指说程序等待 ...