tarjan-无向连通图割点(弱鸡解析+模板)

 费了好大劲,从网上爬来的目前能接受这个,直接改了点的模板...     <<思路来自这位大佬http://www.cnblogs.com/nullzx/,每看一次,理解就更深了一点>>

 

思路:

假设DFS中我们从顶点U访问到了顶点V(此时顶点V还未被访问过),那么我们称顶点U为顶点V的父顶点,V为U的孩子顶点。在顶点U之前被访问过的顶点,我们就称之为U的祖先顶点

1.显然如果顶点U的所有孩子顶点可以不通过父顶点U而访问到U的祖先顶点,那么说明此时去掉顶点U不影响图的连通性,U就不是割点。相反,如果顶点U至少存在一个孩子顶点,必须通过父顶点U才能访问到U的祖先顶点,那么去掉顶点U后,顶点U的祖先顶点和孩子顶点就不连通了,说明U是一个割点。(low(v)>=dfn(u),原理见数据结构部分)

2.我们还需要考虑一个特殊情况,就是DFS的根顶点(一般情况下是编号为0的顶点),因为根顶点没有祖先顶点。其实根顶点是不是割点也很好判断,如果从根顶点出发,一次DFS(即从根节点的一条边出发)就能访问到所有的顶点,那么根顶点就不是割点。反之,如果回溯到根顶点后,还有未访问过的顶点,需要在邻接顶点上再次进行DFS,根顶点就是割点。(son>1  ,构造过程见代码)

 

 (看思路时,仔细对照这张图)

 

数据结构:

dfn数组表示时间戳,子顶点的dfn值一定比父顶点的dfn值大,在访问一个顶点后,它的dfn的值就确定下来了,不会再改变。

low数组中的值表示DFS中该顶点不通过父顶点能访问到的祖先顶点中最小的顺序值(或者说时间戳),在DFS中,我们根据情况不断更新low的值。如果:

  dfn[v] < low[u]

  那么

  low[u] = dfn[v]

如果顶点U还有它分支,每个分支回溯时都进行上述操作,那么顶点low[u]就表示了不通过顶点U的父节点所能访问到的最早祖先节点。

 

代码应用:

Tarjan算法从图的任意顶点开始跑都可以得出割点集和割边集。

对于求割点和割边,因为是无向图(且图连通) 若图连通 tarjan只需运行一次,就可以把图跑完。若非连通,需要多次跑。

 

c++ 代码

int now,root=1,low[maxn],dfn[maxn]; //now是时间    //root是根节点,一般从tarjan()默认1开始,root也为1 
vector<int> g[maxn];
int cut[maxn]; //存储每个点是否是割点
void init(){
    now=0;
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    memset(cut,0,sizeof(cut));
    for(int i=0;i<maxn;i++) g[i].clear();
}
void tarjan(int u,int father){
    int son=0;
    dfn[u]=low[u]=++now;
    for(int i=0; i<g[u].size(); i++){
        int v=g[u][i];
        if(dfn[v]&&v!=father)
            low[u]=min(low[u],dfn[v]);
        if(dfn[v]==0){
            tarjan(v,u);
            son++;
            low[u]=min(low[u],low[v]);
            if((u==root&&son>1)||(u!=root&&dfn[u]<=low[v])) //1.根节点连接至少两个子图     2.非根节点,子节点无法不通过父节点而回到祖先节点
                cut[u]=1;
        }
    }
}
tarjan(1,-1); 

 

转载于:https://www.cnblogs.com/jjl0229/p/11305675.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值