tarjan 缩点 + 几道例题

tarjan 缩点 + 几道例题

tarjan 模板

#include <iostream>
#include <string.h>
using namespace std;
const int MAX_N = 100;
const int MAX_M = 10000;

struct edge{
    int v,next;
    int len;
}E[MAX_M];

int p[MAX_N],eid;
int dfn[MAX_N],low[MAX_N];
int idx = 0;
int belong[MAX_N],scc = 0;
int s[MAX_N],top = 0;
bool in_stack[MAX_N];

void init(){
    memset(p,-1,sizeof(p));
    eid = 0;
}

void insert(int u,int v){
    E[eid].v = v;
    E[eid].next = p[u];
    p[u] = eid++;
}

void tarjan(int u){
    dfn[u] = low[u] = ++idx;
    s[top++] = u;
    in_stack[u] = true;
    for(int i=p[u];i+1;i=E[i].next){
        int v = E[i].v;
        if(!dfn[v]){
            tarjan(v);
            low[u] = min(low[u],low[v]);
        }else if(in_stack[v]){
            low[u] = min(low[u],dfn[v]);
        }
    }
    if(dfn[u] == low[u]){
        ++scc;
        do{
            belong[s[--top]] = scc;
            in_stack[s[top]] = false;
        }while(s[top] != u);
    }
}

int main() {
    int n,m;
    init();
    cin>>n>>m;
    for(int i=0;i<m;i++){
        int u,v;
        cin>>u>>v;
        insert(u,v);
    }
    memset(dfn,0,sizeof(dfn));
    idx = 0;
    for(int i=1;i<=n;i++){
        if(!dfn[i]){
            tarjan(i);
        }
    }
    for(int i=1;i<=scc;i++){
        cout<<"block "<<i<<": ";
        for(int j=1;j<=n;j++){
            if(belong[j] == i){
                cout<<j<<" ";
            }
        }
        cout<<endl;
    }
    return 0;
}

例题1:受欢迎的蒜头



题解地址:https://blog.csdn.net/qq_29980371/article/details/77963431

例题2:发现环(蓝桥杯第八届国赛)

题解地址:https://blog.csdn.net/cillyb/article/details/72802229

例题3:河南省第十二届ACM省赛

G题:tarjan缩点,求出强连通分量数量,统计入度为0的点,但是这样做的人都wa了。。暂且先放在这篇博文里,等时机成熟再补题。

例题4:noip2015信息传递

tarjan找最小环
https://www.luogu.org/problemnew/solution/P2661?page=2

更多:https://www.cnblogs.com/stxy-ferryman/p/7779347.html
求割点和桥:https://www.cnblogs.com/geloutingyu/p/6758624.html
求割点和桥:https://www.jianshu.com/p/d765427e07df
加上两句话:
if(dfn[u] <= low[v]) f = true;
if((!fa && son>1) || (fa && f)) cutp.push_back(u);

vector <int>  cutp;//存放割点
void dfs(int u, int fa){
    dfn[u] = low[u] = ++timer;
    int son = 0;
    bool f = false;
    for(int i=0;i<E[u].size();i++){
        int v = E[u][i];
        if(v == fa) continue;
        if(!dfn[v]){
            son++;
            dfs(v, u);
            if(dfn[u] <= low[v]) f = true;
            low[u] = min(low[u], low[v]);
        }
        else low[u] = min(low[u], dfn[v]);
    }
    if((!fa && son>1) || (fa && f)) cutp.push_back(u);
}
原文地址:https://www.cnblogs.com/fisherss/p/10902324.html