AcWing1174 受欢迎的牛(tarjan缩点)
Posted ctyakwf
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AcWing1174 受欢迎的牛(tarjan缩点)相关的知识,希望对你有一定的参考价值。
对于有向图问题,如果能转化成dag那么就会好做很多,因为这题如果是dag,那么只要只存在一格出度为0的,就是答案
而强连通分量中的点都可以互达,所以进行tarjan缩点。
tarjan缩点的原理,分为四个边,树边,前向边,后向边,横叉边
dfn是时间戳,tarjan的栈中存的是祖先和已被遍历的并且能够走到当前节点祖先或者本身的点,以及本身。
而low数组存的是只经过一条后向边或者横叉边可以走到的dfn最小的并且能够走到当前节点祖先或者本身的点,也就是栈中的点
#include<bits/stdc++.h> using namespace std; const int N=2e5+10; int id[N]; int h[N],ne[N],w[N],e[N],idx; stack<int> q; int scnt; int cnt[N]; int times; int n,m; int dfn[N],low[N]; int ins[N]; int in[N]; void tarjan(int u){ dfn[u]=low[u]=++times; int i; q.push(u),ins[u]=1; for(i=h[u];i!=-1;i=ne[i]){ int j=e[i]; if(!dfn[j]){ tarjan(j); low[u]=min(low[u],low[j]); } else if(ins[j]){ low[u]=min(low[u],dfn[j]); } } if(dfn[u]==low[u]){ ++scnt; while(1){ int t=q.top(); q.pop(); ins[t]=0; cnt[scnt]++; id[t]=scnt; if(t==u) break; } } } void add(int a,int b){ e[idx]=b,ne[idx]=h[a],h[a]=idx++; } int main(){ cin>>n>>m; int i; memset(h,-1,sizeof h); for(i=1;i<=m;i++){ int a,b; scanf("%d%d",&a,&b); add(a,b); } for(i=1;i<=n;i++){ if(!dfn[i]) tarjan(i); } int j; for(i=1;i<=n;i++){ for(j=h[i];j!=-1;j=ne[j]){ int k=e[j]; if(id[i]!=id[k]){ in[id[i]]++; } } } int sum=0; int sign=0; for(i=1;i<=scnt;i++){ if(!in[i]){ sum+=cnt[i]; sign++; } if(sign>1){ sum=0; break; } } cout<<sum<<endl; }
以上是关于AcWing1174 受欢迎的牛(tarjan缩点)的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ10511051: [HAOI2006]受欢迎的牛 tarjan求强连通分量+缩点