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

题目传送门

\(Tarjan\)缩点,缩点后找入度为\(0\)的点的数量(第一问),第二问是取\(max(\)入度为\(0\)的点的数量,出度为\(0\)的点的数量\()\)

P.S.别忘了特判缩成一个点的情况

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct zzz{
    int f,t,nex;
}e[10010<<1]; int head[110],tot;
void add(int x,int y){
    e[++tot].f=x;
    e[tot].t=y;
    e[tot].nex=head[x];
    head[x]=tot;
}
int read(){
    int k=0; char c=getchar();
    for(;c<'0'||c>'9';) c=getchar();
    for(;c>='0'&&c<='9';c=getchar())
      k=(k<<3)+(k<<1)+c-48;
    return k;
}
int dfn[110],low[110],deth,s[110],top,belong[110],col;
bool vis[110];
void tarjan(int f){
    dfn[f]=low[f]=++deth;
    s[++top]=f,vis[f]=1;
    for(int i=head[f];i;i=e[i].nex){
        int to=e[i].t;
        if(!dfn[to]){
            tarjan(to);
            low[f]=min(low[f],low[to]);
        }
        else
          if(vis[to]) low[f]=min(low[f],dfn[to]);
    }
    if(dfn[f]==low[f]){
        col++;
        int k=0;
        do{
            k=s[top--];
            belong[k]=col;
            vis[k]=0;
        }while(k!=f);
    }
}
int in[110],out[110],innum,outnum;
int main(){
    int n=read();
    for(int i=1;i<=n;i++)
      while(int k=read())
        add(i,k);
    for(int i=1;i<=n;i++)
      if(!dfn[i]) tarjan(i);
    for(int i=1;i<=tot;i++){
        int x=e[i].f,y=e[i].t;
        if(belong[x]!=belong[y])
          in[belong[y]]++, out[belong[x]]++;
    }
    for(int i=1;i<=col;i++){
        if(!in[i]) innum++;
        if(!out[i]) outnum++;
    }
    printf("%d\n%d",innum,col==1? 0:max(innum,outnum));
    
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/wxl-Ezio/p/9374251.html
今日推荐