Tarjan强连通分量

强连通分量(Tarjan)

个人认为:求强连通分量的过程就是缩点的过程

算法主要步骤

  1. 时间戳
  2. 和它子树中的返祖边和横插边能连到还没有出栈的的最小的点
  3. 的时候维护一个栈,第一次访问某一个节点时就把这个点加入到栈中,当一个点时,它就是这个强连通分量在搜索树中最高的点,将栈里的点出栈,知道点也出栈,这些点构成一个强连通分量

一些思考

  1. 时,它就不能通过返祖边或者横插边去到比它更靠上的点了
  2. 理解它的正确性:
    • 在dfs中,先出栈的点一定能被后出栈的点到达
    • 越是靠后出栈就越有可能到达不了 (
    • 所以当访问到了一个的点时,一定是通过横插边或者返祖边回到了之前某个点,也就组成了一个强连通分量

代码

const int maxn = 1e5;
int dfn[maxn], low[maxn];
int col[maxn]; // 每个点属于哪一个强连通分量
bool vis[maxn]; // 是否在我维护的栈中
int cnt = 0;
int num = 0; // 有几个强连通分量
std::stack<int> stk;
std::vector<int> edge[maxn];
void tarjan(int x)
{
    dfn[x] = low[x] = ++cnt;
    vis[x] = 1;
    stk.push(x);
    for (int i = 0; i < edge[i].size(); i++)
    {
        int y = edge[x][i];
        if (dfn[y] == 0) // 树边
        {
            tarjan(y);
            low[x] = std::min(low[x], low[y]);
        }
        else if (vis[y] == 1) // 在栈中才有效 返祖边或横插边
        {
            low[x] = std::min(low[x], dfn[y]);
        }
    }
    if (low[x] == dfn[x])
    {
        num++;
        while(true)
        {
            int top = stk.top(); 
            col[top] = num;
            vis[top] = 0;
            stk.pop();
            if (x == top) break;
        }
    }
}
全部评论

相关推荐

点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务