有向图中所有点都能到达的点
题意
题目大概是有好多牛,牛(们)之间具有某种关系(鬼知道),这种关系具有传递性,如果有 A欢迎B和B欢迎C,那么就有A欢迎C。我们要找到能让其他所有的牛都欢迎的牛。
思路
画图易知
如果强联通分量中有多个缩点,出度为零,要么不成联通,要么联通也不能被所有牛崇拜,故而本题求的是唯一的一个出度为零的连通分量的规模
Ps:对于入度没有要求(画蛇添足必须死)
代码
/*
* Author : Echo
* Email : 1666424499@qq.com
* Description :
* Created Time : 2017/10/15 17:54:39
* Last Modify : 2017/10/15 19:03:40
* File Name : write.cpp
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string>
using namespace std;
const int maxn=1e5+100;
const int maxm=1e6;
const int INF=1e9;
struct edge {
int to,next;
}an[maxm];
int head[maxn];
int dfn[maxn]; //入栈时间戳
int ins[maxn]; //是否入栈
int low[maxn]; //最早发现时间
int stk[maxn]; //手工栈
int dot[maxn]; //缩点
int out[maxn]; //出度
int ind[maxn]; //入度
int m=0;//edge
int cntm;
int top;//stack
int cnt;//dot
int n;//point
int tm;//time
void addedge(int u,int v){
an[++cntm].to=v;
an[cntm].next=head[u];
head[u]=cntm;
}
void tarjan(int u){
dfn[u]=low[u]=++tm;
stk[++top]=u;
ins[u]=1;
for(int i=head[u];i!=-1;i=an[i].next){
int v=an[i].to;
if(dfn[v]==0){
tarjan(v);
if(low[u]>low[v]) low[u]=low[v];
}
else if(ins[v]&&low[u]>low[v]){
low[u]=low[v];
}
}
if(low[u]!=dfn[u]) return;
int v=stk[top--];
ins[v]=0;
dot[v]=++cnt;
while(u!=v){
v=stk[top--];
ins[v]=0;
dot[v]=cnt;
}
}
int main(){
//while(~scanf("%d",&n)){
scanf("%d%d",&n,&m);
top=cnt=tm=0;
for(int i=1;i<=n;i++){
dfn[i]=ins[i]=out[i]=ind[i]=0;
head[i]=-1;
}
for(int i=1;i<=m;i++){
int u,v;
scanf("%d%d",&u,&v);
addedge(u,v);
}
for(int i=1;i<=n;i++){
if(dfn[i]) continue;
tarjan(i);
}
for(int u=1;u<=n;u++){
for(int i=head[u];i!=-1;i=an[i].next){
int v=an[i].to;
if(dot[u]==dot[v])continue;
out[dot[u]]++;
ind[dot[v]]++;
}
}
int ans1=0,ans2=0,ans=0;
for(int i=1;i<=cnt;i++){
if(ind[i]==0) ans1++;
if(out[i]==0) ans2++;
}
if(ans2>1){
printf("0\n");
return 0;
}
for(int i=1;i<=n;i++){
if(out[dot[i]]) continue;
ans++;
}
printf("%d\n",ans);
//}
return 0;
}