tarjan+缩点模板
#include<set> #include<map> #include<list> #include<queue> #include<stack> #include<string> #include<cmath> #include<ctime> #include<vector> #include<bitset> #include<memory> #include<utility> #include<cstdio> #include<sstream> #include<iostream> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; const int N=500005; stack <int> q; int tot,n,m,num,ans; int head[N],next[N],to[N],dfn[N],low[N],f[N]; bool visit[N]; int get(){//快读,不加的话超时一个点 char zy=getchar(); int zyy=1,zzy=0; while(zy>‘9‘||zy<‘0‘){ if(zy==‘-‘){ zyy=-1; } zy=getchar(); } while(zy<=‘9‘&&zy>=‘0‘){ zzy=zzy*10+zy-‘0‘; zy=getchar(); } return zyy*zzy; } inline int mi(int a,int b){return a<b?a:b;} inline int ma(int a,int b){return a>b?a:b;} inline void add(int u,int v){//链式前向星 next[++tot]=head[u]; head[u]=tot; to[tot]=v; } void tarjan(int u){//tarjan板子,并由缩点的预处理 dfn[u]=low[u]=++tot; visit[u]=1; q.push(u); for(int i=head[u];i;i=next[i]){ if(!dfn[to[i]]){ tarjan(to[i]); low[u]=mi(low[u],low[to[i]]); } else if(visit[to[i]]){ low[u]=mi(low[u],low[to[i]]); } } if(dfn[u]==low[u]){ int v; num++; do{ v=q.top(); q.pop(); visit[v]=0; f[v]=num;//缩点的预处理 }while(v!=u&&!q.empty()); } } int main(){ n=get(); m=get(); for(int i=1;i<=m;i++){ int u,v; u=get(); v=get(); if(u!=v){//去除自环的情况 add(u,v); } } tot=0; for(int i=1;i<=n;i++){ if(!dfn[i]){ tarjan(i); } } memset(visit,0,sizeof(visit)); for(int i=1;i<=n;i++){ for(int j=head[i];j;j=next[j]){ if(f[i]!=f[to[j]]){ visit[f[to[j]]]=true;//与其求入度,在本题中还不如直接表示是否有点指向自身,便于理解 } } } for(int i=1;i<=num;i++){ ans+=(!visit[i]);//表示没有节点指向自己,需要直接接收消息 } printf("%d\n",ans); return 0; }
原文:https://www.cnblogs.com/ainiyuling/p/11156807.html