#include<cstdio>
#include<cstring>
using namespace std;
const int N=1e4+5;
const int M=5e4+5;
int i,j,k=0,n,m,num=0,col=0;
struct node{ int v,next;}e[M];
int first[N],chu[N]={0},dfn[N]={0},low[N]={0},belong[N];
bool vis[N];
int st[N],top=0;
int read(){
int s=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){ if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){ s=(s<<3)+(s<<1)+ch-48;ch=getchar();}
return s*f;
}
void add(int u1,int v1){
e[++k].v=v1;e[k].next=first[u1];first[u1]=k;
}
int min(int x,int y){if(x<y) return x;return y;}
void trijan(int u){
dfn[u]=low[u]=++num;//dfn[u]表示dfs时达到顶点u的次序号(时间戳),low[u]表示以u为根节点的dfs树中次序号最小的顶点的次序号
st[++top]=u; //将u入栈
vis[u]=1; //标记u在栈内
for(int i=first[u];i;i=e[i].next){
int v=e[i].v; //边的起点为u,终点为v
if(!dfn[v]){ //如果v未被处理过
trijan(v); //深搜v
low[u]=min(low[u],low[v]);//u点能到达的最小次序号是它自己能到达点的最小次序号和连接点v能到达点的最小次序号中较小的
}
else{
if(vis[v]) //如果v点在栈中
low[u]=min(low[u],dfn[v]); //u点能到达的最小次序号是它自己能到达点的最小次序号和v的次序号中较小的
}
}
if(dfn[u]==low[u]){
belong[u]=++col; //标记u属于第col个强连通分量
while(st[top]!=u){
belong[st[top]]=col;
vis[st[top]]=0;
--top;
}
--top;
}
}
int main(){
memset(first,0,sizeof(first));
memset(vis,0,sizeof(vis)); //将所有点都标记为未在栈中
n=read();m=read();
for(int i=1;i<=m;++i){
int u1=read(),v1=read();
add(u1,v1);
}
for(int i=1;i<=n;++i)
if(!dfn[i]) trijan(i);
//for(int i=1;i<=n;++i) printf("%d:%d\n",i,belong[i]);
for(int i=1;i<=n;++i)
for(int j=first[i];j;j=e[j].next)
if(belong[i]!=belong[e[j].v]) chu[belong[i]]++; //统计每个强连通分量的出度值
int t=0,p=0;
for(int i=1;i<=col;++i)
if(chu[i]==0){ t++;p=i; }; //寻找出度为0的强连通分量值
if(t!=1) printf("0");
else{
int ans=0;
for(int i=1;i<=n;++i)
if(belong[i]==p) ans++;
printf("%d",ans);
}
return 0;
}
强连通分量
最新推荐文章于 2021-08-12 01:07:14 发布