图论-强连通分量

这是一份 Tarjan 求强连通分量的板子

其中和求割点,割边相同:
dfn[ ] 表示为时间戳数组
back[ ] 表示为能访问到的最远祖先(如果该祖先暂无SCC)


针对求解强联通分量,需要多定义如下变量

  1. stack<int> st; 用于存放 dfs 中的路径,从栈顶一直到 这个点本身(指 dfs 中 u)的点就是一个scc
  2. int sccno[ ]; 表示这个点属于第几个 scc

点击查看代码
int head[N], cnt;
struct Edge{
    int from, to, nxt;
}e[N << 1];
void add(int u, int v){
    e[++cnt].from = u;
    e[cnt].to = v;
    e[cnt].nxt = head[u];
    head[u] = cnt;
}

int ans_scc, sccno[N], dfn[N], back[N], tim;
stack<int> st;
void dfs(int u){
    st.push(u);
    dfn[u] = back[u] = ++tim;
    for(int i = head[u]; i != 0; i = e[i].nxt){
        int v = e[i].to;
        if(!dfn[v]){
            dfs(v);
            back[u] = min(back[u], back[v]);
        }else if(!sccno[v]){
            back[u] = min(back[u], dfn[v]);
            // back[u] = min(back[u], back[v]);
        }
    }
    if(back[u] == dfn[u]){
        ans_scc++;
        while(1){
            int v = st.top();
            st.pop();
            sccno[v] = ans_scc;
            if(u == v) break;
        }
    }
}

void Tarjan(int n){
    ans_scc = tim = 0;
    memset(sccno, 0, sizeof(sccno));
    memset(dfn, 0, sizeof(dfn));
    memset(back, 0, sizeof(back));
    for(int i = 1; i <= n; i++){
        if(!dfn[i])
            dfs(i);
    }
}

其中代码为

else if(!sccno[v]){
	back[u] = min(back[u], dfn[v]);
   // back[u] = min(back[u], back[v]);  这个也可以,与割点不同
}

有以下几点注意点:有以下几点注意点:

1. 在有向图中,back[i] 数组的意义更新了,现在一个点可以通过其祖先节点访问到更祖先的节点,结果显然成立,因为是有向图,并且求解问题不同。于是back[u] = min(back[u], back[v]);成立
2.笔者归结 Tarjan 的简化理解步骤2.笔者归结 Tarjan 的简化理解步骤
- 所有节点都想往上爬(将自己的能力提升),规定所有节点的能力只能依靠自己和子节点的能力,而不能依靠祖先节点的能力,证明也很显然,如果自己和儿子都不争气,不能连接到更先的父节点,那就只能自己成为一个 scc 了
- 当 dfs 到了节点 u 时,此时 u 为根节点,拓展下去一颗“树”,首先,大家起始的能力就是自己,当然“辈分越大,能力也越大”,当 dfs 到了节点 u 时,此时 u 为根节点,拓展下去一颗“树”,首先,大家起始的能力就是自己,当然“辈分越大,能力也越大”

于是,事情就变成了,所有节点都在期待一个突然爆发的子节点(或者靠本身),能使它本身连接到一个 dfn 最小的祖先节点。然后,针对节点 u ,
如果它与它子节点的努力得到了回报(指 back[u] < dfn[u]),那么递归返回到 u 时,就不用在 u 处更新一个新的 scc ,而在 u 的祖先节点处更新一个更大的 scc ;
如果(back[u] == dfn[u]),说明这个分支到此为止了,所有存在 stack 里的点都是这个 scc 的一员

posted @   9102700  阅读(11)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
  1. 1 鼓楼 赵雷
  2. 2 我们的歌 王力宏
  3. 3 老街 李荣浩
  4. 4 周杰伦
  5. 5 可惜没如果 林俊杰
  6. 6 不将就 李荣浩
  7. 7 南方姑娘 赵雷
  8. 8 南方姑娘(弹唱版) 赵雷
  9. 9 如果可以 韦礼安
  10. 10 写给黄淮 邵帅
  11. 11 我想念 汪苏泷
  12. 12 雨天 汪苏泷
  13. 13 雨天雨天 汪苏泷
  14. 14 成都 赵雷
我们的歌 - 王力宏
00:00 / 00:00
An audio error has occurred, player will skip forward in 2 seconds.

作词 : 王力宏/陈信延

作曲 : 王力宏

编曲 : 王力宏

已经听了一百遍

已经听了一百遍

怎么听都不会倦

从白天唱到黑夜

你一直在身边

如果世界太危险

只有音乐最安全

带着我进梦里面

让歌词都实现

无论是开心还是难过我的爱一直不变

不必担心时间流逝带走一切

无论是Hip-Hop 还是摇滚我的爱一直不变

所有美好回忆记录在里面

这种 Forever Love 那么深

我们的歌 那么真

无国界跨时代

再也不会叫我Kiss Goodbye

要每一句能够动人心弦 Yeah

情人总分分合合

可是我们却越爱越深

认识你 让我的幸福如此悦耳

能不能不要切歌

继续唱我们的歌​​

让感动一辈子都记得

已经听了一百遍

已经听了一百遍

怎么听都不会倦

从白天唱到黑夜

你一直在身边

如果世界太危险

只有音乐最安全

带着我进梦里面

让歌词都实现

无论是开心还是难过我的爱一直不变

不必担心时间流逝带走一切

无论是Hip-Hop 还是摇滚我的爱一直不变

所有美好回忆记录在里面

这种 Forever Love 那么深

我们的歌 那么真

无国界跨时代

再也不会叫我Kiss Goodbye

要每一句能够动人心弦 Yeah

情人总分分合合

可是我们却越爱越深

认识你 让我的幸福如此悦耳

能不能不要切歌

继续唱我们的歌​​

让感动一辈子都记得

情人总分分合合

情人总分分合合

可是我们却越爱越深

认识你 让我的幸福如此悦耳

能不能不要切歌

继续唱我们的歌​​

让感动一辈子都记得

电吉他/其他乐器:王力宏

鼓手:Eric Fawcrtt

贝斯:John Mumson

录音师/录音室:王力宏/Homeboy Music Studios,Taipei

OP:HIM Music Publishing Inc.

OP:Homeboy Music,Inc,Taiwan

SP:Sony Music Publishing(Pre)Ltd.Taiwan Branch

点击右上角即可分享
微信分享提示