Tarjan

来源:互联网 发布:入职培训 it 编辑:程序博客网 时间:2024/06/05 18:29
Tarjan是多种算法的总称,因为Tarjan这个人太牛X了,那我们今天就来看一看Tarjan神的算法之一 :Tarjan求割边割点;首先我们要清晰什么是割边割点:    割点:         首先我们有一张连通图:

这里写图片描述

对于这张图,显然它是一张联通图,那么割点的定义就是:“某一个点A,若删除这个点并且删去这个点所练的边,那么这张图的强联通分量增多”;

若删除点3及相连的边后,强联通分量就变成了{1,2}和{4,5,6} (点3已删除);

那么割边呢?

显然,根据割点的定义,割边的定义可以推得:“某一条边B,若删除该边,则所在图的强联通分量增多”;这个定义和割点的定义极其相似;

则,在上图中,若删除3—4这条边,改图的强联通分量数目改变,由{1,2,3,4,5,6}—>{1,2,3}和{4,5,6};所以,该图中3—4这条边就是该图的割边;

同样,一重点内容个图中的割点割边有时候不止一个;

而Tarjan是怎么求割边割点呢??!
用一个dfs的思想,建一棵搜索树;
然后我们有一个结论:

割点:<1> 若这个点A是根节点,那么只要它有两棵及以上的子树,那么它必为割点;
<2> 若这个点A不是根节点,则如果它所有儿子的LOW都小于等于节点A的DFN,则节点A是割点;

割边同样可以类比割点的性质;
割边:<1> 若该节点A,与它的子节点B,若节点B的LOW小于A的DFN,则A——B是割边;

割点:证明<1>:若该根节点A含有两棵及以上子树,则删去节点A,其子树必定成为独立的强联通分量,且数量增多;反之,若只含有一棵子树,则节点A删除后对原图联通性毫无影响;

割点:证明<2>:若节点A非根节点,且没有一个儿子的LOW小于A的DFN,即没有回边指向节点A的祖先,所以以节点A为根的子树是通过节点A来连接到整棵树上的,所以删除节点A后,该子树脱落,强联通分量增加;

割边:证明<1>:若节点A的儿子B,LOW[B]>DFN[A] ,则以B为根节点的子树是由A——B这条边连接到整棵树中的,所以删除A——B,该子树脱落,强联通分量增加;

作为一个程序员,我们看重的不能只有思想,还要有代码:

void Tarjan(int x){    int child=0;    DFN[x]=LOW[x]=++_num;    for(R II i=head[x];i;i=aa[i].up)    {        R II go=aa[i].to;        if(!DFN[go]){            child++;            fa[go]=x;            Tarjan(go);            if(LOW[go]>DFN[x]) ...            // x 和 go所连的边是一条割边;            LOW[x]=min(LOW[go],LOW[x]);            if(LOW[go]>=DFN[x]&&x!=root)  bit[x]=1;            // x 是根时 ,x 是一个割点;             if(x==root&&child>1)  bit[x]=1;            // x 不是根时 ,x 是割点;         }        else{            if(go!=fa[x]){                LOW[x]=min(LOW[x],DFN[go]);            }        }    }}for(int i=1;i<=n;i++)// 原图不一定是一个强联通分量;{    if(!DFN[i]){        root=i;        Tarjan(i);    }}

by aTm;
如有错误,请留言,感谢光临!!
END;

原创粉丝点击