LOJ-10094(强连通分量)

题目链接:传送门

思路:

先缩点,然后统计入度为0的点即可。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 1e6+10;
int num[maxn],low[maxn],tim,col,co[maxn];
int head[maxn],next[maxn],ver[maxn],tot;
int st[maxn],top,in[maxn];
int MIN(int x,int y)
{
    return x<y?x:y;
}
void Init()
{
    memset(num,0,sizeof(num));
    memset(low,0,sizeof(low));
    memset(head,0,sizeof(head));
    memset(next,0,sizeof(next));
    memset(ver,0,sizeof(ver));
    memset(co,0,sizeof(co));
    tot=0;tim=0;col=0;top=0;
}
void addedge(int x,int y)
{
    ver[++tot]=y;next[tot]=head[x];head[x]=tot;
}
void Tarjan(int u)
{
    int v,i;
    low[u]=num[u]=++tim;
    st[++top]=u;
    for(i=head[u];i;i=next[i]){
        v=ver[i];
        if(!num[v]){
            Tarjan(v);
            low[u]=MIN(low[u],low[v]);
        }
        else if(!co[v]) low[u]=MIN(low[u],num[v]);
    }
    if(low[u]==num[u]){
        col++;
        co[u]=col;
        while(st[top]!=u){
            co[st[top]]=col;
            top--;
        }
        top--;
    }
}
int main(void)
{
    int n,i,j,x;
    scanf("%d",&n);
    Init();
    for(i=1;i<=n;i++){
        for(j=1;j<=n;j++){
            scanf("%d",&x);
            if(x) addedge(i,j);
        }
    }
    for(i=1;i<=n;i++)
    if(!num[i]) Tarjan(i);
     
    for(i=1;i<=n;i++){
        for(j=head[i];j;j=next[j]){
            if(co[i]!=co[ver[j]]) in[co[ver[j]]]++;
        }
    }
    int cnt=0;
    for(i=1;i<=col;i++)
    if(in[i]==0) cnt++;
    printf("%d
",cnt);
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/2018zxy/p/10368197.html