洛谷 P2746 [USACO5.3]校园网 Network of Schools 题解

Tarjan 模板题

第一问就是缩点之后看有多少个入度为零的点就好了。

第二问是在缩点后将每个点的入度和出度都求出(只要有入度或出度就置为1),然后比较哪个有值的多,将多的作为答案输出。原因是由题可得,要使缩完的点也构成一个强连通分

量,即入度和出度都大于等于1。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #define maxn 10010
  6 using namespace std;
  7 inline int read() 
  8 {
  9     int x=0;
 10     bool f=1;
 11     char c=getchar();
 12     for(; !isdigit(c); c=getchar()) if(c=='-') f=0;
 13     for(; isdigit(c); c=getchar()) x=(x<<3)+(x<<1)+c-'0';
 14     if(f) return x;
 15     return 0-x;
 16 }
 17 inline void write(int x)
 18 {
 19     if(x<0){putchar('-');x=-x;}
 20     if(x>9)write(x/10);
 21     putchar(x%10+'0');
 22 }
 23 struct node
 24 {
 25     int v,nex;
 26 }edge[maxn];
 27 int n,cnt,inl,top,res1,res2,num,cd2,rd2;
 28 int head[maxn],st[maxn],low[maxn],dfn[maxn],inn[maxn],si[maxn],rd[maxn],cd[maxn];
 29 inline void add(int x,int y)
 30 {
 31     cnt++;
 32     edge[cnt].v=y;
 33     edge[cnt].nex=head[x];
 34     head[x]=cnt;
 35 }
 36 inline void Tarjan(int from) 
 37 {
 38     dfn[from]=low[from]=++num;
 39     st[++top]=from;
 40     for(int i=head[from];i!=-1;i=edge[i].nex)
 41     {
 42         int to=edge[i].v;
 43         if(!dfn[to])
 44         {
 45             Tarjan(to);
 46             low[from]=min(low[from],low[to]);
 47         }
 48         else if(!inn[to])
 49             low[from]=min(low[from],dfn[to]);
 50     }
 51     if(low[from]==dfn[from])
 52     {
 53         inn[from]=++inl;
 54         ++si[inl]; 
 55         while(st[top]!=from)
 56         {
 57             ++si[inl];
 58             inn[st[top]]=inl;
 59             --top;
 60         }
 61         --top;
 62     }
 63 }
 64 int main()
 65 {
 66     memset(head,-1,sizeof(head));
 67     n=read();
 68     for(int i=1;i<=n;i++)
 69     {
 70         int x;
 71         while(1)
 72         {
 73             x=read();
 74             if(x!=0)add(i,x);
 75             else break;
 76         }
 77     }
 78     for(int i=1;i<=n;i++)
 79         if(!dfn[i])
 80             Tarjan(i);
 81     for(int i=1;i<=n;i++)
 82        for(int j=head[i];j!=-1;j=edge[j].nex)
 83        {
 84             if(inn[i]!=inn[edge[j].v])
 85             {
 86                 rd[inn[edge[j].v]]++;
 87                 cd[inn[i]]++;
 88             }
 89 
 90        }
 91     if(inl==1)
 92     {
 93         cout<<1<<endl<<0;
 94         return 0;
 95     }
 96     for(int i=1;i<=inl;i++)
 97         if(rd[i]==0)
 98             res1++;
 99     write(res1);
100     cout<<endl;
101     for(int i=1;i<=inl;i++)
102     {
103         if(cd[i]==0)
104             cd2++;
105         if(rd[i]==0)
106             rd2++;
107     }
108     res2=max(cd2,rd2);
109     write(res2);
110     return 0;
111 }
请各位大佬斧正(反正我不认识斧正是什么意思)

 

posted @ 2019-07-24 14:27  handsome_zyc  阅读(183)  评论(0编辑  收藏  举报