求强连通分量几种算法的比较
来源:互联网 发布:淘宝运送方式怎么设置 编辑:程序博客网 时间:2024/05/29 14:51
对于求有向图的强连通分量 , 我常用的一般只有这三种算法Kosaraju、Tarjan、Garbow,而这三种算法 ,Tarjan和Garbow算法的思想是一样的 , 只不过是实现的方法不一样 , 下面就逐一分析这三个算法:
1、Kosaraju
Kosaraju算法主要是利用有向图中原图和其反图之间的关系, 对于一个原图中的强连通分量 , 其在反图中还是强连通分量 , 原图中存在u 到 v的边 , 在反图中就只存在 v 到 u的边 ,而不存在u 到 v的边。 根据这个关系 , 我们先用原图进行dfs搜索 , 得到了一个森林(树) ,我们再按照原图中得到的dfs搜索序列 , 在其反图中进行dfs搜索 , 每次搜索能遍历到的顶点就是一个强连通分量。
代码:
//Kosaraju算法
int dfsone(int cur)
{
temp[cur] =true;
for(int i =head[cur] ; i != -1; i = edge[i].next)
{
if(!temp[edge[i].t]) dfsone(edge[i].t);
}
num[++sig] =cur;
return0;
}
int dfstwo(int cur , int sig)
{
temp[cur] =true;
scc[cur] =sig;
for(int i =head2[cur] ; i != -1; i = edge[i].next2)
{
if(!temp(edge[i].f))
dfstwo(edge[i].f , sig);
}
return0;
}
int Kosaraju()
{
int sig =0;
memset(temp, 0 , sizeof(temp));
for(int i =1; i <=n ; i++)
{
if(!temp[i])
dfsone(i ,sig);
}
sig =0;
memset(temp, 0 , sizeof(temp));
for(int i =n; i > 0; i--)
{
if(!temp[num[i]])
{
dfstwo(num[i] , sig++);
}
}
returnsig;
}
2、Tarjan算法
Tarjan是利用跟求割点和桥的算法的思想差不多 ,都是利用dfs + 时间戳 。
如果对原图进行dfs搜索 , 那么我们有强连通分量的定义可知, 任何一个强连通分量是原图的dfs搜索的子树 , 那么我们只要确定了强连通分量在dfs序列中的根 , 我们就能确定这个强连通分量 。在进行dfs时 , 我们用两个数组tem 、 low来记录每个点的时间戳 , low记录每个点的访问时间 ,tem记录所有子孙的最小low值 ,tem的初始值和low一样 。 所以在dfs搜索的回溯过程中 , 如果low[v] ==tem[v] , 我们我们就能确定一个强连通分量。
代码:
//tarjan算法
void dfs(int u)
{
node.push(u);
low[u] =tem[u] = ++dfs_clock;
int i;
for(i =head[i] ; i != -1; i = edge[i].next)
{
v =edge[i].to;
if(!pre[v])
{
pre[v] =1;
int lowv = =dfs(v);
tem[u] =min(lowv , tem[u]);
}
elseif(!sccno[i]) tem[u] = min(tem[u] ,tem[v]);//tem是记录每个点的子孙所能到达的low最小的点
}
if(low[u] ==tem[u])
{
scc_clock++;
do
{
int x =node.top(); node.pop();
1、Kosaraju
代码:
//Kosaraju算法
int dfsone(int cur)
{
}
int dfstwo(int cur , int sig)
{
}
int Kosaraju()
{
}
2、Tarjan算法
代码:
//tarjan算法
void dfs(int u)
{