https://www.byvoid.com/blog/scc-tarjan

主要思想

Tarjan算法是基于对图深度优先搜索的算法,每个强连通分量为搜索树中的一棵子树。搜索时,把当前搜索树中未处理的节点加入一个堆栈,回溯时可以判断栈顶到栈中的节点是否为一个强连通分量。

定义DFN(u)为节点u搜索的次序编号(时间戳),Low(u)为u或u的子树能够追溯到的最早的栈中节点的次序号。由定义可以得出,

Low(u)=Min

{

DFN(u),

Low(v),(u,v)为树枝边,u为v的父节点

DFN(v),(u,v)为指向栈中节点的后向边(非横叉边)

}

当DFN(u)=Low(u)时,以u为根的搜索子树上所有节点是一个强连通分量。

因此很容易理解..

算法伪代码如下

tarjan(u)
{
DFN[u]=Low[u]=++Index // 为节点u设定次序编号和Low初值
Stack.push(u) // 将节点u压入栈中
for each (u, v) in E // 枚举每一条边
if (v is not visted) // 如果节点v未被访问过
tarjan(v) // 继续向下找
Low[u] = min(Low[u], Low[v])
else if (v in S) // 如果节点v还在栈内
Low[u] = min(Low[u], DFN[v])
if (DFN[u] == Low[u]) // 如果节点u是强连通分量的根
repeat
v = S.pop // 将v退栈,为该强连通分量中一个顶点
print v
until (u== v)
}

C++代码:

void tarjan(int i)
{
int j;
DFN[i]=LOW[i]=++Dindex;
instack[i]=true;
Stap[++Stop]=i;
for (edge *e=V[i];e;e=e->next)
{
j=e->t;
if (!DFN[j])
{
tarjan(j);
if (LOW[j]<LOW[i])
LOW[i]=LOW[j];
}
else if (instack[j] && DFN[j]<LOW[i])
LOW[i]=DFN[j];
}
if (DFN[i]==LOW[i])
{
Bcnt++;
do
{
j=Stap[Stop--];
instack[j]=false;
Belong[j]=Bcnt;
}
while (j!=i);
}
}
void solve()
{
int i;
Stop=Bcnt=Dindex=0;
memset(DFN,0,sizeof(DFN));
for (i=1;i<=N;i++)
if (!DFN[i])
tarjan(i);
}

自己的版本:

#include <set>
#include <queue>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <map>
#include <string>
#include <stack>
using namespace std;
int N,M;
string NAME[40];
map<string,int> dict;
stack<int> S;
int tot=0; //这一道题特有的存点..
int cnt=0; //强连通数目
int time=0; //时间戳
int DFN[40],Low[40]; //DNF 时间戳,Low ,u及u的子树最小的时间戳
bool INSTACK[40]; //判断是否在栈内
int Belong[40]; //存储属于哪一个强连通分量;
struct Edge{
int to;
Edge *next;
}E[20000],*EE;
struct Node{
Edge *first;
}G[50];
void Link(int a,int b)
{
EE->to=b;EE->next=G[a].first;G[a].first=EE++;
}
void input()
{
EE=E;
tot=0;
time=0;
cnt=0;
string a,b;
dict.clear();
memset(G,0,sizeof(G));
memset(DFN,0,sizeof(DFN));
for(int i=1;i<=M;i++)
{
cin>>a>>b;
if(dict[a]==0)
{
dict[a]=++tot;
NAME[tot]=a;
}
if(dict[b]==0)
{
dict[b]=++tot;
NAME[tot]=b;
}
Link(dict[a],dict[b]);
}
}
void Tarjan(int u)
{
DFN[u]=Low[u]=++time;
S.push(u);
INSTACK[u]=true;
for(Edge *p=G[u].first;p;p=p->next)
{
if(DFN[p->to]==0)
{
Tarjan(p->to);
Low[u]=min(Low[u],Low[p->to]);
}
else if(INSTACK[p->to]==true)
Low[u]=min(Low[u],DFN[p->to]);
}
int k;
if(DFN[u]==Low[u])
{
int ok=0;
cnt++;
do
{
k=S.top();
S.pop();
INSTACK[k]=false;
Belong[k]=cnt;
if(ok==0)
{
ok=1;
cout<<NAME[k];
}
else cout<<", "<<NAME[k];
}while(k!=u);
cout<<endl;
}
}
void solve()
{
for(int i=1;i<=N;i++)
{
if(DFN[i]==0)
Tarjan(i);
}
}
int main()
{
int CASE=0;
// freopen("a.in","r",stdin);
while(cin>>N>>M&&(N||M))
{
printf("Calling circles for data set %d:\n",++CASE);
input();
solve();
}
}

[有向图的强连通分量][Tarjan算法]的更多相关文章

  1. 【有向图】强连通分量-Tarjan算法

    好久没写博客了(都怪作业太多,绝对不是我玩的太嗨了) 所以今天要写的是一个高大上的东西:强连通 首先,是一些强连通相关的定义 //来自度娘 1.强连通图(Strongly Connected Grap ...

  2. 有向图强连通分量 Tarjan算法

    [有向图强连通分量] 在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly connected).如果有向图G的每两个顶点都强连通,称G是一个强连通图.非强连通图有向图的极 ...

  3. 有向图强连通分量Tarjan算法

    在https://www.byvoid.com/zhs/blog/scc-tarjan中关于Tarjan算法的描述非常好,转述如下: 首先解释几个概念: 有向图强连通分量:在有向图G中,如果两个顶点间 ...

  4. 图之强连通、强连通图、强连通分量 Tarjan算法

    原文地址:https://blog.csdn.net/qq_16234613/article/details/77431043 一.解释 在有向图G中,如果两个顶点间至少存在一条互相可达路径,称两个顶 ...

  5. 图的连通性:有向图强连通分量-Tarjan算法

    参考资料:http://blog.csdn.net/lezg_bkbj/article/details/11538359 上面的资料,把强连通讲的很好很清楚,值得学习. 在一个有向图G中,若两顶点间至 ...

  6. 图论-强连通分量-Tarjan算法

    有关概念: 如果图中两个结点可以相互通达,则称两个结点强连通. 如果有向图G的每两个结点都强连通,称G是一个强连通图. 有向图的极大强连通子图(没有被其他强连通子图包含),称为强连通分量.(这个定义在 ...

  7. POJ1236_A - Network of Schools _强连通分量::Tarjan算法

    Time Limit: 1000MS   Memory Limit: 10000K Description A number of schools are connected to a compute ...

  8. 强连通分量——tarjan算法

    概念: 有向图强连通分量:在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通.如果有向图G的每两个顶点都强连 ...

  9. 求图的强连通分量--tarjan算法

    一:tarjan算法详解 ◦思想: ◦ ◦做一遍DFS,用dfn[i]表示编号为i的节点在DFS过程中的访问序号(也可以叫做开始时间)用low[i]表示i节点DFS过程中i的下方节点所能到达的开始时间 ...

随机推荐

  1. ThinkPHP实现跨模块调用操作方法概述

    ThinkPHP实现跨模块调用操作方法概述 投稿:shichen2014 字体:[增加 减小] 类型:转载   使用 $this 可以调用当前模块内的方法,但是很多情况下经常会在当前模块中调用其他模块 ...

  2. PHP学习笔记十八【构造函数】

    <?php class Person{ public $name; public $age; //定义构造函数 function 空格__construct 构造方法没有返回值,对象自动调用 p ...

  3. CGContext

    CGContext又叫图形上下文,相当于一块画布,以堆栈形式存放,只有在当前 context上绘图才有效.iOS有分多种图形上下文,其中UIView自带提供的在drawRect:方法中通过 UIGra ...

  4. 判断两个View的GRect是否相等

    if (CGRectEqualToRect(self.view.frame, rect)) { // do some stuff }

  5. web验证码

    前台引用.aspx: <%@ Page Language="C#" AutoEventWireup="true" CodeFile="YanZh ...

  6. Lucene学习总结之八:Lucene的查询语法,JavaCC及QueryParser

    一.Lucene的查询语法 Lucene所支持的查询语法可见http://lucene.apache.org/java/3_0_1/queryparsersyntax.html (1) 语法关键字 + ...

  7. CSS3动画之百度钱包

    百度钱包的步骤:1.建一个盒子,里面放两个盒子,代表正反面,两个盒子叠一起,正面层次高2.当鼠标Hover时,正面盒子从0deg->-180deg,反面盒子从-180deg->0deg3. ...

  8. 蜘蛛牌(hdu 1584 DFS)

    蜘蛛牌 Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submis ...

  9. information_schema.key_column_usage 学习

    information_schema.key_column_usage 表可以查看索引列上的约束: 1.information_schema.key_column_usage 的常用列: 1.cons ...

  10. [TYVJ] P1044 数字三角形

    数字三角形 背景 Background 09年 USACO 11月月赛  铜牌第一道   描述 Description 示出了一个数字三角形. 请编一个程序计算从顶至底的某处的一条路径,使该路径所经过 ...