Tarjan算法总结

强联通分量

点击查看代码
#include<bits/stdc++.h>

using namespace std;

int n,m;
vector<int> e[10005];

int dfn[10005],low[10005],timtp;
int stk[10005],stktp;
bool instk[10005];
int scccnt,inscc[10005];
vector<int> scc[10005];
bool vis[10005];

void tarjan(int x){

    dfn[x] = low[x] = ++timtp;
    stk[++stktp] = x;instk[x] = 1;
    for(auto y:e[x]){
        if(!dfn[y]){
            tarjan(y);
            low[x] = min(low[x],low[y]);
        }
        else if(instk[y]) low[x] = min(low[x],dfn[y]);
    }

    if(low[x] >= dfn[x]){
        scccnt++;
        int y;
        do{
            y = stk[stktp--];
            instk[y] = 0;
            inscc[y] = scccnt;
            scc[scccnt].push_back(y);
        }while(y != x);
    }
    
}

signed main(){

    cin >> n >> m;
    for(int i = 1;i <= m;++ i){
        int u,v;
        cin >> u >> v;
        e[u].push_back(v);
    }

    for(int i = 1;i <= n;++ i)
        if(!dfn[i]) tarjan(i);

    cout << scccnt << endl;
    for(int i = 1;i <= n;++ i){
        if(vis[inscc[i]]) continue;
        vis[inscc[i]] = 1;
        int w = inscc[i];
        sort(scc[w].begin(),scc[w].end());
        for(auto x:scc[w]) cout << x << " ";
        cout << endl;
    }
    
    return 0;
    
}

缩点

点击查看代码
#include<bits/stdc++.h>

#define int long long

using namespace std;

int n,m;
int a[10005];
struct bian{
    int u,v;
}b[100005];
vector<int> e[10005];
vector<int> e2[10005];
int a2[10005];

int dfn[10005],low[10005],timtp;
int stk[10005],stktp;
int instk[10005];
int beinscc[10005];
int cntscc;
int sizscc[10005];

void dfs(int x){

    dfn[x] = low[x] = ++timtp;
    stk[++stktp] = x;instk[x] = 1;

    for(auto y:e[x]){
        if(!dfn[y]){
            dfs(y);
            low[x] = min(low[x],low[y]);
        }
        else if(instk[y]) low[x] = min(low[x],dfn[y]);
    }

    if(low[x] == dfn[x]){
        cntscc++;
        int y;
        do{
            y = stk[stktp--];
            instk[y] = 0;
            sizscc[cntscc] += a[y];
            beinscc[y] = cntscc;
        }while(y != x);
    }
    
}

int ind[10005];
int ds[10005];

signed main(){

    cin >> n >> m;
    for(int i = 1;i <= n;++ i)
        cin >> a[i];
    for(int i = 1;i <= m;++ i){
        int u,v;
        cin >> u >> v;
        b[i] = {u,v};
        e[u].push_back(v);
    }

    for(int i = 1;i <= n;++ i)
        if(!dfn[i]) dfs(i);

    for(int i = 1;i <= m;++ i){
        if(beinscc[b[i].u] != beinscc[b[i].v]){
            int u = beinscc[b[i].u];
            int v = beinscc[b[i].v];
            e2[u].push_back(v);
            ind[v]++;
        }
    }
    for(int i = 1;i <= cntscc;++ i)
        a2[i] = sizscc[i];

    queue<int> q;
    for(int i = 1;i <= cntscc;++ i)
        if(ind[i] == 0) ds[i] = a2[i],q.push(i);
    while(!q.empty()){
        int x = q.front();q.pop();
        for(auto y:e2[x]){
            ds[y] = max(ds[y],a2[y]+ds[x]);
            ind[y]--;
            if(!ind[y]) q.push(y);
        }
    }

    int ans = 0;
    for(int i = 1;i <= cntscc;++ i)
        ans = max(ans,ds[i]);
    cout << ans;
    
    return 0;
    
}

割点

点击查看代码
#include<bits/stdc++.h>

using namespace std;

int n,m;
vector<int> e[20005];

int dfn[20005],low[20005],timtp;
int gdcnt,isgd[20005];

void tarjan(int x,int com){

    dfn[x] = low[x] = ++timtp;

    int child = 0;
    for(auto y:e[x]){
        if(!dfn[y]){
            tarjan(y,com);
            low[x] = min(low[x],low[y]);
            child++;
            if(low[y] >= dfn[x]&&x != com)
                gdcnt += (!isgd[x]),isgd[x] = 1;
        }
        else low[x] = min(low[x],dfn[y]);
    }

    if(x == com&&child >= 2) gdcnt += (!isgd[x]),isgd[x] = 1;
    
}

signed main(){

    cin >> n >> m;
    for(int i = 1;i <= m;++ i){
        int u,v;
        cin >> u >> v;
        e[u].push_back(v);
        e[v].push_back(u);
    }

    for(int i = 1;i <= n;++ i)
        if(!dfn[i]) tarjan(i,i);

    cout << gdcnt << endl;
    for(int i = 1;i <= n;++ i)
        if(isgd[i]) cout << i << " ";
    
    return 0;
    
}

点双联通分量

点击查看代码
#include<bits/stdc++.h>

using namespace std;

int n,m;
vector<int> e[500005];

int dfn[500005],low[500005],timtp;
int stk[500005],stktp;
int scccnt;
vector<int> scc[500005];

void tarjan(int x,int root){

    dfn[x] = low[x] = ++timtp;
    stk[++stktp] = x;

    int child = 0;
    for(auto y:e[x]){
        if(!dfn[y]){
            tarjan(y,root);
            low[x] = min(low[x],low[y]);
            if(low[y] >= dfn[x]){
                scccnt++;
                int w;
                do{
                    w = stk[stktp--];
                    scc[scccnt].push_back(w);
                }while(w != y);
                scc[scccnt].push_back(x);
            }
            child++;
        }
        else low[x] = min(low[x],dfn[y]);
    }

    if(x == root&&child == 0)
        scc[++scccnt].push_back(x);
    
}

signed main(){

    cin >> n >> m;
    for(int i = 1;i <= m;++ i){
        int u,v;
        cin >> u >> v;
        e[u].push_back(v);
        e[v].push_back(u);
    }

    for(int i = 1;i <= n;++ i)
        if(!dfn[i]) stktp = 0,tarjan(i,i);

    cout << scccnt << endl;
    for(int i = 1;i <= scccnt;++ i){
        cout << scc[i].size() << " ";
        for(auto x:scc[i]) cout << x << " ";
        cout << endl;
    }
    
    return 0;
    
}

边双联通分量

点击查看代码
#include<bits/stdc++.h>

using namespace std;

int n,m,w_wo_o;
vector<pair<int,int> > e[500005];

int dfn[500005],low[500005],timtp;
int scccnt;
vector<int> scc[500005];
int stk[500005],stktp;

void tarjan(int x,int com){

    dfn[x] = low[x] = ++timtp;
    stk[++stktp] = x;

    for(auto [y,whe]:e[x]){
        if(!dfn[y]){
            tarjan(y,whe);
            low[x] = min(low[x],low[y]);
        }
        else if(whe != (com^1)) low[x] = min(low[x],dfn[y]);
    }

    if(low[x] == dfn[x]){
        scccnt++;
        int w;
        do{
            w = stk[stktp--];
            scc[scccnt].push_back(w);
        }while(w != x);
    }
    
}

signed main(){

    cin >> n >> m;
    for(int i = 1;i <= m;++ i){
        int u,v;
        cin >> u >> v;
        e[u].push_back({v,w_wo_o++});
        e[v].push_back({u,w_wo_o++});
    }

    for(int i = 1;i <= n;++ i)
        if(!dfn[i]) stktp = 0,tarjan(i,-1);

    cout << scccnt << endl;
    for(int i = 1;i <= scccnt;++ i){
        cout << scc[i].size() << " ";
        for(auto x:scc[i]) cout << x << " ";
        cout << endl;
    }
    
    return 0;
    
}

没有栈的是:割点,点双
本文中的缩点是割边,但平常要视情况而定。

posted @ 2025-11-25 20:55  我的晴语表  阅读(10)  评论(0)    收藏  举报