tarjan求强联通分量

tarjan求强联通分量

变量含义说明:

pre[i]:i点的被访问的时钟编号,被分配后保持不变
low[i]:i点能访问的最先的点的时钟编号,随子节点改变
scc_no[i]:i点所在的强联通分量的编号
dfs_clock:时钟序号,每访问一个新的点时都增长1
scc_cnt:强联通分量的编号
栈stk:每访问一个节点都压入栈中

他的步骤如下所述:

  1. 从根节点开始访问
  2. 为此新点的pre和low赋值现在的时间
  3. 遍历访问它的子节点
    如果此点未被访问,则跳回第二步,然后跟新其low值
    如果已访问但其未进入强联通编号,则用此点pre更新父节点的low值
  4. 遍历完子节点后,如果发现此点的low值和pre值相等,则说明它是所在强联通分量的拥有最小时间访问编号的那个点,于是可以从栈stk中弹出他的后续所有节点,并为他们赋值一个新的强联通分量的编号。

具体代码如下;

@Frosero

#include <iostream>
#include <cstring>
#include <stack>
#include <vector>

int low[202],pre[202],scc_no[202],dfs_clock,scc_cnt;
vector<int>mps[202];
stack<int>stk;

void tarjan(int s){
    pre[s] = low[s] = ++dfs_clock;
    stk.push(s);
    for(int i=0;i<mps[s].size();i++){
        int v = mps[s][i];
        if(!pre[v]){
            tarjan(v);
            low[s] = min(low[s],low[v]);
        }
        else if(!sccno[v]){
            low[s] = min(low[s],pre[v]);
        }
    }

    if(pre[s] == low[s]){
        scc_cnt++;
        while(true){
            int x = stk.top(); stk.pop();
            sccno[x] = scc_cnt;
            if(x == s) break;
        }
    }
}

void fin_circle(int s){
    memset(pre,0,sizeof(pre);
    dfs_clock = scc_cnt = 0;
    tarjan(s);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值