Tarjan算法(缩强连通子图为节点)

//Tarjan算法(将强连通分量缩度再进行处理)  //POJ 2186
#include<iostream>
#include<cstdio>
#include<stack>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 1e4 + 15;
vector<int> Grape[maxn];
int cnt;//缩度的节点个数
int arr[maxn];//缩点的标号
bool vis[maxn];
int dfn[maxn],low[maxn],total;//total用来标序号
int du[maxn];
stack<int> s;
void tarjan(int u)
{
    dfn[u] = low[u] = ++total;
    s.push(u);
    vis[u] = true;//入栈
    for(int i=0;i!=Grape[u].size();++i)
    {
        int v = Grape[u][i];
        if(!dfn[v])
        {
            tarjan(v);
            low[u] = min(low[u],low[v]);
        }else if(vis[v])//如果在栈中存在
        {
            low[u] = min(low[u],dfn[v]);
        }
    }
    if(dfn[u]==low[u])//如果节点为强连通图的根
    {
        int v = 0;
        ++cnt;
        do{
            v = s.top();
            s.pop();
            vis[v] = false;
            arr[v] = cnt;
        }while(u!=v);
    }
}
int main()
{
    int n,m;
    while(cin>>n>>m)//n个节点,m条边
    {
        for(int i=1;i<=n;++i)
            Grape[i].clear();
        int u,v;
        for(int i=1;i<=m;++i)
        {
            cin>>u>>v;
            Grape[u].push_back(v);
        }
        //Tarjan算法缩度
        cnt = 0,total = 0;
        memset(dfn,0,sizeof(dfn));
        memset(low,0,sizeof(low));
        memset(du,0,sizeof(du));//Judge node不为 0 的出度个数
        memset(arr,0,sizeof(arr));
        for(int u=1;u<=n;++u)
        {
            if(!dfn[u])
            {
                tarjan(u);
            }
        }
        for(int u=1;u<=n;++u)
        {
            for(int i=0;i!=Grape[u].size();++i)
            {
                int v = Grape[u][i];
                if(arr[u]!=arr[v])
                    ++du[arr[u]];//u 节点所在的环
            }
        }
        int num = 0,pos = 0;
        for(int v=1;v<=cnt;++v)
        {
            if(du[v]==0)
            {
                ++num;
                pos = v;
            }
        }
        if(num!=1)
            cout<<0<<endl;
        else{
            int ans = 0;
            for(int i=1;i<=n;++i)
                if(arr[i]==pos)
                    ++ans;
            cout<<ans<<endl;
        }
    }
}
不怕万人阻挡,只怕自己投降。
原文地址:https://www.cnblogs.com/newstartCY/p/11573279.html