洛谷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