Tarjan缩点

思路

这个算法的实在含义就是把图中所有强连通分量缩成一个点,然后把图变成一个DAG。

所以,自然的,其实就是求强连通分量而已。

Tarjan求强连通分量的原理、细节与模板

模板

//建图
struct graph{
    int cnt;
    int hd[N],ne[M],to[M],ed[M];
    void adde(int a,int b,int c=0){
        to[++cnt]=b;
        ne[cnt]=hd[a];
        hd[a]=cnt;
        ed[cnt]=c;
    }
}ori,aft;//原图&缩点后图
int n,m;
int u,v;

//缩点
int scnt;
int scc[N],siz[N];
int dcnt;
int dfn[N],low[N];
bool ins[N];
stack<int> stk;
void tarjan(int rt){
    dfn[rt]=low[rt]=++dcnt;
    stk.push(rt);ins[rt]=true;
    for(int e=ori.hd[rt];e;e=ori.ne[e]){
        int nxt=ori.to[e];
        if(dfn[nxt]==0){
            tarjan(nxt);
            low[rt]=min(low[rt],low[nxt]);
        }
        else if(ins[nxt])low[rt]=min(low[rt],dfn[nxt]);
    }
    if(dfn[rt]==low[rt]){
        scnt++;
        while(true){
            int tp=stk.top();
            stk.pop();ins[tp]=false;
            scc[tp]=scnt;
            siz[scnt]++;
            if(stk.top()==rt)break;
        }
    }
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    cin>>n>>m;
    for(int i=1;i<=m;i++){
        cin>>u>>v;
        ori.adde(u,v);
    }
    for(int i=1;i<=n;i++){
        if(dfn[i]==0)tarjan(i);
    }
//在新图上连边
    for(int i=1;i<=n;i++){
        for(int e=ori.hd[i];e;e=ori.ne[e]){
            int j=ori.to[e];
            if(scc[i]!=scc[j]){
                aft.adde(scc[i],scc[j]);
            }
        }
    }
    return 0;
}

例题

LG-P3387

代码 前注:非题解,不做详细讲解。
#include<bits/stdc++.h>
using namespace std;

#define fir first
#define sec second
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef pair<ll,int> pli;
typedef pair<int,ll> pil;
typedef pair<ll,ll> pll;
typedef pair<int,pii> pip;
typedef vector<int> veci;
typedef priority_queue<int> bghp;
typedef priority_queue<int,vector<int>,greater<int> > lthp;

const int mod=998244353;
const int N=1e4+5,M=1e5+5;

struct graph{
    int cnt;
    int hd[N],ne[M],to[M],ed[M];
    void adde(int a,int b,int c=0){
        to[++cnt]=b;
        ne[cnt]=hd[a];
        hd[a]=cnt;
        ed[cnt]=c;
    }
}ori,aft;

int n,m;
int u,v;
int a[N];

int scnt;
int scc[N],siz[N];
int dcnt;
int dfn[N],low[N];
bool ins[N];
stack<int> stk;
void tarjan(int rt){
    dfn[rt]=low[rt]=++dcnt;
    stk.push(rt);ins[rt]=true;
    for(int e=ori.hd[rt];e;e=ori.ne[e]){
        int nxt=ori.to[e];
        if(dfn[nxt]==0){
            tarjan(nxt);
            low[rt]=min(low[rt],low[nxt]);
        }
        else if(ins[nxt])low[rt]=min(low[rt],dfn[nxt]);
    }
    if(dfn[rt]==low[rt]){
        scnt++;
        while(stk.top()!=rt){
            int tp=stk.top();
            stk.pop();ins[tp]=false;
            scc[tp]=scnt;
            siz[scnt]+=a[tp];
        }
        stk.pop();ins[rt]=false;
        scc[rt]=scnt;
        siz[scnt]+=a[rt];
    }
}

int f[N];
int ans;
int dg[N];
void topo(graph &g){
    queue<int> q;
    for(int i=1;i<=g.cnt;i++){
        dg[g.to[i]]++;
    }
    for(int i=1;i<=scnt;i++){
        f[i]=siz[i];
        if(dg[i]==0)q.push(i);
    }
    while(!q.empty()){
        int now=q.front();q.pop();
        for(int e=g.hd[now];e;e=g.ne[e]){
            int nxt=g.to[e];
            f[nxt]=max(f[nxt],f[now]+siz[nxt]);
            if(--dg[nxt]==0)q.push(nxt);
        }
    }
    for(int i=1;i<=scnt;i++){
        ans=max(ans,f[i]);
    }
}

int main(){
    // freopen(".in","r",stdin);
    // freopen(".out","w",stdout);
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    for(int i=1;i<=m;i++){
        cin>>u>>v;
        ori.adde(u,v);
    }
    for(int i=1;i<=n;i++){
        if(dfn[i]==0)tarjan(i);
    }
    for(int i=1;i<=n;i++){
        for(int e=ori.hd[i];e;e=ori.ne[e]){
            int j=ori.to[e];
            if(scc[i]!=scc[j]){
                aft.adde(scc[i],scc[j]);
            }
        }
    }
    topo(aft);
    cout<<ans;
    return 0;
}
posted @ 2024-10-15 13:46  HarlemBlog  阅读(6)  评论(0编辑  收藏  举报