Tarjan双连通分量算法论文翻译

32 篇文章 0 订阅
30 篇文章 0 订阅


Depth-First Search and Linear Graph Algorithms


        Tarjan在1972年发表了这篇关于线性图论算法的论文,在论文中详细分析了深度优先搜索的各种性质,并且利用其性质给出了两个应用:无向图双连通分量以及有向图强连通分量
        在此将对其中的双连通分量算法做出一些翻译解释。仅需要你对DFS发现时间以及后向边有了解即可。

一、首先给出一些定义:

  1. 树边:深度优先森林(无相连通图中深搜树T)中的边。
  2. 后向边:后向边(u,v)是将点u连接到其深度优先搜索树中的一个祖先节点v的边。
  3. Palm Tree(简称P):由树边和无向边以及这些点构成的图。
  4. 双连通图:设G = (V,E)为一无向连通图,对于V中的每三个点v,w,a,都有一条路径从v到w而不用经过a,我们就称G为双连通图。
  5. 关节点:设G中三点v,w,a,若任何从v到w的路径(至少有一条)都要经过a,我们就称a为G的一个关节点。

  • 注意虽然双连通分量值针对于无向图,但是其DFS生成的P以及T都是有向图,T是P的子图。

    于是有引理:设G  = (V,E),若定义位于同一环路的边为等效边,则根据此将边进行划分Ei,边的端点集Vi,则我们称Gi = (Vi,Ei)为G的一个双连通分量。

双连通分量有以下性质:

  1. Gi之间互不包含。
  2. G中每个关节点至少出现一次在Vi中,每个非关节点都只出现在 一个Vi里面。
  3. Vi与Vj(i != j)交集最多只有一个元素,这个元素也就是图G的关节点。

二、双连通分量定理及实现


       设number[u]为点u的发现时间,low[u]为点u在palm tree中能到达的最早点的发现时间。

       定理:设无向连通图中三点u,v,a若(a,v)是T(不包括后向边)也即是P的一条边,并且u不是v在T中的子孙节点,如果low[v] >= number[a],则a是G的一个关节点并且去掉a以后v和u将不会连通。

      证明:因为a可到v并且low[v] >= a,所以从v出发的点若不经过a则只能在v以及v的子孙节点中,又因为u不是v在T中的子孙节点,所以a是G的一个关节点。

       上图是论文中的一个例子,图(a)表示无向连通图,图(b)给出了palm tree,点旁边的记号分别为发现时间以及low值,带星号的点为关节点。其中的后向边由虚线给出。

为了进一步分析问题,给出求双连通分量的代码:

int BiConnect(short v,short u)  //u is the father of v in spanning T
{
    number[v] = low[v] = index++;
    for(short w = 1;w <= N;w++)
    {
        if(w != u&&w != v&&graph[v][w])    //可行边并且不能是其本身以及其父节点
        {
            edge newEdge;
            newEdge.x = v;
            newEdge.y = w;
            if(!number[w])      //w还没标记,则w将是v的一个子节点
            {
                edgeStack[stackTop++] = newEdge;       //将边压入栈
                BiConnect(w,v);                         //继续深搜
                low[v] = min(low[v],low[w]);           //深搜返回后调整low值
                if(low[w] >= number[v])                //有双连通分量或者桥边
                {
                    memset(bcc,0,sizeof(bcc));
                    while((--stackTop)&&(edgeStack[(stackTop)].x != newEdge.x||edgeStack[(stackTop)].y != newEdge.y))   //将直到(v,w)的边出栈
                    {
                        bcc[edgeStack[stackTop].x][edgeStack[stackTop].y] = 1;      //将边保存到双连通分量bcc
                    }
                    bcc[edgeStack[stackTop].x][edgeStack[stackTop].y] = 1;
                }
            }
            else if(number[w] < number[v])      //(v,w)是后向边,说明有环路
            {
                edgeStack[stackTop++] = newEdge;
                low[v] = min(low[v],number[w]);
            }
        }
    }
    return 0;
}

  • 在代码中,无向图以及双连通分量都是采用的矩阵表示。
  • 根据tarjan算法,我们不断将遇到的树边以及后向边(只能是这两种边)压入栈,若遇到Low[w] >= number[v],则进行出栈以及双连通分量处理。注意此时的v不一定是关节点,(v,w)也不一定是桥(删除此边,图就不再连通)
  1. 首先分析为什么不是么关节点,可以很容易举出反例,若G就是个单纯的环路,则DFS会一直往下走直到又回到根节点时,不等式等号成立,而根节点又显然不是关节点,单纯的环路图就没有关节点。这个与Tarjan的定理矛盾吗?当然是不矛盾的,注意定理题设中给出了三点,也即是必须还要有一点u不在v的生成树中,但是环路中,所有点(除了根节点)都在根节点的子树中了。所以求关节点时,代码中当v为根节点时,还要看DFS后子节点是否有超过两个,有的话则v是一个关节点(不同子树的点必须通过根节点连接)。
  2. 同样若G是单纯环路,则(v,w)显然也不是桥,注意到此时G是个双连通图,所有点的low值都等于number[root],所以不等式取等号说明(v,w)是双连通分量中的边,取大于号说明是桥。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值