[HAOI2006]受欢迎的牛

[Time Gate]

https://www.luogu.org/problemnew/show/P2341

【解题思路】

由题可得,受欢迎的奶牛只有可能是图中唯一的出度为零的强连通分量中的所有奶牛,
所以若出现两个以上出度为0的强连通分量则不存在明星奶牛,
因为那几个出度为零的分量的爱慕无法传递出去。
那唯一的分量能受到其他分量的爱慕同时在分量内相互传递,所以该分量中的所有奶牛都是明星。

【code】
 1 #include<bits/stdc++.h>
 2     #define N 10050
 3     using namespace std;
 4     struct EDGE{
 5         int next,to;
 6     }edge[N*20];
 7     int head[20*N],dfn[N],low[N];
 8     int du[N],id[N],all[N];
 9     bool insta[N];int cnt,tot,gg,n,m;
10     stack<int>s;
11     inline void add(int x,int y){
12         cnt++;
13         edge[cnt].to=y;
14         edge[cnt].next=head[x];
15         head[x]=cnt;
16     }
17     void in(int &read){
18         int x=0,f=1;char ch;
19         for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
20         if(ch=='-'){f=-1;ch=getchar();}
21         while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
22         read=x*f;//可以处理负数的读入优化
23     }
24     void tarjan(int x){
25         dfn[x]=low[x]=++tot;
26         s.push(x);insta[x]=true;
27         for(int i=head[x];i;i=edge[i].next){
28             int u=edge[i].to;
29             if(!dfn[u]){
30                 tarjan(u);
31                 low[x]=min(low[x],low[u]);
32             }
33             else if(insta[u])low[x]=min(low[x],dfn[u]);
34         }//tarjan模板
35         int k;
36         if(low[x]==dfn[x]){
37             ++gg;
38             do{
39                 k=s.top();s.pop();
40                 insta[k]=false;
41                 id[k]=gg;all[gg]++;//将一个分量中的元素染成一色
42             }while(x!=k);
43         }
44     }
45     int main(){
46         in(n);in(m);
47         int a,b;
48         for(register int i=1;i<=m;i++){
49             in(a);in(b);
50             add(a,b);
51         }
52         for(register int i=1;i<=n;i++)
53             if(!dfn[i])tarjan(i);
54         for(register int w=1;w<=n;w++){
55             for(int i=head[w];i;i=edge[i].next){
56                 int u=edge[i].to;
57                 if(id[w]!=id[u]){
58                     du[id[w]]++;//遍历每一个点并记录出度
59                 }
60             }
61         }
62         int tt=0;
63         for(register int i=1;i<=gg;i++)
64             if(!du[i]){
65             if(tt){puts("0");return 0;}//两次出现出度为0直接输出0
66             tt=i;//记录出度为零的分量的边号
67         }
68         printf("%d\n",all[tt]);
69         return 0;
70 }
FINISHED!
posted @ 2019-07-08 20:24  GTR_PaulFrank  阅读(142)  评论(0编辑  收藏  举报