tarjan——校园网(缩点,再构图)

P2746 [USACO5.3]校园网Network of Schools

任务一:求缩完点后入度为0的点的个数(有向边)

任务二:求缩完点后入度为0和出度为0的最大值(要把图构造成强连通分量)

注意,任务二需要特判整张图是一个强联通

#include<cstdio>
#include<cstring>
#include<stack>
#include<algorithm>
using namespace std;
const int maxn=20100;
int pre[maxn],other[maxn],last[maxn],l;
int n;
void add(int x,int y)
{
    l++;
    pre[l]=last[x];
    last[x]=l;
    other[l]=y;
}
int dfn[maxn],low[maxn];
int cnt;
int belong[maxn],qw;
int ru[maxn];
stack<int> s;
void dfs(int x)
{
    low[x]=dfn[x]=++cnt;
    s.push(x);
    //ru[x]=1;
    for(int p=last[x];p;p=pre[p])
    {
        int v=other[p];
    //    if(v==fa) continue;
        if(!dfn[v])
        {
            dfs(v);
            low[x]=min(low[x],low[v]);
        }
        else if(!belong[v])
        {
            low[x]=min(low[x],dfn[v]);
        }
    }
    if(dfn[x]==low[x])
    {
        belong[x]=++qw;
        while(1)
        {
            int y=s.top();
            s.pop();
            //ru[y]=0;
            belong[y]=qw;
            if(y==x) break;
        }
    }
}
int ans1,ans2;
int chu[maxn];
int main()
{
    scanf("%d",&n);
    for(int i=1,x;i<=n;i++) while(scanf("%d",&x)&&x){add(i,x);}
    for(int i=1;i<=n;i++)
    {
        if(!dfn[i]) 
        {
            dfs(i);
        }
    }
    for(int i=1;i<=n;i++)
    {
        for(int p=last[i];p;p=pre[p])
        {
            int v=other[p];
            if(belong[i]!=belong[v])
            {
                chu[belong[i]]++;
                ru[belong[v]]++;
            }
        }
    }
    for(int i=1;i<=qw;i++)
    {
        if(!ru[i]) ans1++;
        if(!chu[i]) ans2++;
    }
    if(qw==1)
    {
        printf("1\n0");
        return 0;
    }
    printf("%d\n",ans1);
    printf("%d",max(ans1,ans2));
    return 0;
}

 

posted @ 2019-09-18 16:26  AiRomance  阅读(141)  评论(0编辑  收藏  举报