文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>TARJAN 算法求强连通分量

TARJAN 算法求强连通分量

时间:2010-11-07  来源:forever zsz

下图中,子图{1,2,3,4}为一个强连通分量,因为顶点1,2,3,4两两可达。{5},{6}也分别是两个强连通分量。

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

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

Low(u)=Min{DFN(u),Low(v),(u,v)为树枝边,u为v的父节点{

如果下一个要访问的V节点,没有访问过,则low[U]=min(low[u],low[v])。

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

{如果已经在栈中了,则low[U]=min(low[u],dfn[v])

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

依照上面红色字体的定义,只要当DFN[U]=LOW[U] 便说明此时栈中的元素,从元素U以上的栈中元素都属于同一个强连通分量。

  具体的分步分析过程请参考百度文库(http://wenku.baidu.com/view/ceb92fe2524de518964b7d66.html);

下面给出TARJAN算法的具体代码:

#include <cstdio>
#include <cstdlib>
struct
{
      int x,y,n;
}e[1000];
int f[1000];
int o;
bool v[1000];
bool vs[1000];
int b[1000][1000],dfn[1000],low[1000],zhan=0,lian,ti=0;
int stick[1000];
int min(int a,int b)
{
    return (a<b)?a:b;
}
void add(int a,int b)
{
     o++;
     e[o].x=a;
     e[o].y=b;
     e[o].n=f[a];
     f[a]=o;
}
void tanzhan(int u)
{
     lian++;
     int j=1;
     while (stick[zhan]!=u)
     {
           b[lian][j++]=stick[zhan--];
           vs[stick[zhan]]=false;
     }
     b[lian][j++]=stick[zhan];{B数组记录的是每一个强连通分量,及每一个强连通分量中的元素}
     vs[u]=false;
     b[lian][0]=j-1;
}
void tarjan(int u)
{
     dfn[u]=++ti;
     if (low[u]==0) low[u]=dfn[u];
     stick[++zhan]=u;
     vs[u]=true;{VS表示当前元素是否在模拟的栈中}
     int t=f[u];
     v[u]=true;
     while (e[t].y!=0)
     {
           if (v[e[t].y]==false) 
           { 
                                tarjan(e[t].y);
                                low[u]=min(low[u],low[e[t].y]);{由上面红色字体的定义,更新每一个点的LOW值和DFN值}
           }else
           {
                if (vs[e[t].y]==true)
                  low[u]=min(low[u],dfn[e[t].y]);
           }     
           t=e[t].n;           
      }//这里没有回溯的过程,因此TARJAN是O(M+N)的算法。
     if (dfn[u]==low[u]) tanzhan(u);    
}
int main()
{
    int m;
    freopen("tarjan.in","r",stdin);
    freopen("tarjan.out","w",stdout);
    scanf("%d",&m);
    for (int i=1;i<=m;i++)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        add(a,b);
    }
    for (int i=1;i<=6;i++)
    {
        if (v[i]==false) tarjan(i);
    }
    for (int i=1;i<=6;i++)
            {printf("%d\n",dfn[i]);
      printf("%d\n",low[i]);}
    return 0;
}
    
    

图中的元素采用模拟链表存储,其中需要注意的是,因为tarjan算法是只会对每一个图中的节点访问一遍,因此不需要回溯(即V数组,只会更新一遍)

 

相关阅读 更多 +
排行榜 更多 +
坦克冒险大师安卓版

坦克冒险大师安卓版

策略塔防 下载
自动防御

自动防御

策略塔防 下载
枪战大乱斗2

枪战大乱斗2

飞行射击 下载