其他分享
首页 > 其他分享> > 洛谷P2341 [USACO03FALL / HAOI2006] 受欢迎的牛 G (tarjan缩点)

洛谷P2341 [USACO03FALL / HAOI2006] 受欢迎的牛 G (tarjan缩点)

作者:互联网

在本题中很明显,给你一个有向图,要用tarjan缩点。

缩点后,一头牛要受到所有牛的欢迎,那么该点的出度要为0,这是容易证明的:如果该点还有出度,比如a连向b,那么a不受到b的欢迎。所以我们要找出度为0的点,找到后该点中点的个数就是答案。

注意:出度为0的点只能有一个,如果有多个出度为0的点,那么这些点都不受到彼此的欢迎。因此题目有解的情况就是只有一个出度为0的点。

(以上都是缩点后的分析)。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=10010;
 4 int head[N],nxt[N*20],to[N*20],dfn[N],low[N];
 5 int du[N],num[N],sum[N],st[N],top;
 6 int cnt,tot,idx,n,m;
 7 bool vis[N];
 8 void add(int u,int v){
 9     nxt[++tot]=head[u];
10     head[u]=tot;
11     to[tot]=v;
12 }
13 
14 void tarjan(int u){
15     dfn[u]=low[u]=++cnt;
16     st[++top]=u;
17     vis[u]=true;
18     for(int i=head[u];i;i=nxt[i]){
19         int v=to[i];
20         if(!dfn[v]){
21             tarjan(v);
22             low[u]=min(low[u],low[v]);
23         }
24         else if(vis[v]) low[u]=min(low[u],dfn[v]);
25     }
26     if(low[u]==dfn[u]){
27         int vv;
28         ++idx;
29         do{
30             vv=st[top--];
31             vis[vv]=false;
32             num[vv]=idx;
33             sum[idx]++;
34         }while(vv!=u);
35     }
36 }
37 
38 int main(){
39     scanf("%d%d",&n,&m);
40     while(m--){
41         int a,b;
42         scanf("%d%d",&a,&b);
43         add(a,b);
44     }
45     for(int i=1;i<=n;i++)
46         if(!dfn[i]) tarjan(i);
47     for(int i=1;i<=n;i++)
48         for(int j=head[i];j;j=nxt[j])
49             if(num[i]!=num[to[j]]) du[num[i]]++;
50     int x=0;
51     for(int i=1;i<=idx;i++)
52         if(!du[i]){
53             if(x) {puts("0");return 0;}
54             x=i;
55         }
56     printf("%d\n",sum[x]);
57     return 0;
58 }

 

标签:缩点,tarjan,洛谷,int,出度,++,dfn,low,vv
来源: https://www.cnblogs.com/yhxnoerror/p/16364700.html