tarjan算法总结

来源:互联网 发布:glide源码原理 编辑:程序博客网 时间:2024/05/28 23:11

概念(有向图中):

1)在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强连通

2)如果有向图G的每两个顶点都强连通,则称G是一个强连通图

3)非强连通图有向图的极大强连通子图,称为强连通分量


tarjan算法:通过递归和栈操作,找强连通子图,并进行缩点

设每个点的DFS序为dfn[u],当递归到第u个点,发现下一个点v已经被遍历过,且dfn[u]<dfn[v],这两个点一定在一个强连通子图中(构成环)


然后可以用low[u]记录u所在强连通子图中最小的DFS序,对于每个强连通子图,把点都缩为DFS序最小的那个点(即low[u])


缩点方法:进行递归,每次进入函数时都将当前点入栈,每次退出函数时判断当前点u的DFS序是否为u所在强连通子图中的最小DFS序,即dfn[u]==low[u]。如果是,那么就可以将栈中u之后的点全部缩为点u(可以通过vector实现)


#include<bits/stdc++.h>using namespace std;const int MX = 1e3 + 5;stack<int>st;                // 存储已遍历的结点int dfn[MX];                 // 深度优先搜索访问次序int low[MX];                 // 能追溯到的最早的次序int mark[MX];                // 检查是否在栈中(2为在栈中,1为已访问,且不在栈中,0为不在)vector<int> ver[MX];         // 获得强连通分量结果int id[MX];                  // 记录每个点在第几号强连通分量里int index, sz;               // DFS序,强连通分量个数struct Edge {    int v, nxt;} E[MX*MX];int head[MX], tot;void add(int u, int v) {    E[tot].v = v;    E[tot].nxt = head[u];    head[u] = tot++;}void init(int n) {    while (!st.empty()) st.pop();    memset(dfn, 0, sizeof(dfn));    memset(low, 0, sizeof(low));    for (int i = 1; i <= n; ++ i) ver[i].clear();    index = sz = 0;    memset(head, -1, sizeof(head));    tot = 0;}void tarjan(int u) {    mark[u] = 2;    low[u] = dfn[u] = ++ index;    st.push(u);    for (int i = head[u]; ~i; i = E[i].nxt) {        int v = E[i].v;        if (dfn[v] == 0) {            tarjan(v);            low[u] = min(low[u], low[v]);        } else if (mark[v] == 2) low[u] = min(low[u], dfn[v]);    }    if (low[u] == dfn[u]) {        ++ sz;        while (!st.empty()) {            int v = st.top();            st.pop();            mark[v] = 1;            ver[sz].push_back(v);            id[v] = sz;            if (v == u) break;        }    }}void solve(int n){    for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);}int main() {    int n, m;    scanf("%d%d", &n, &m);    init(n);    for (int i = 1; i <= m; i++) {        int u, v;        scanf("%d%d", &u, &v);        add(u, v);    }    solve(n);    printf("%d\n", sz);    return 0;}