简述:
- 缩点+判定(性质)
易错点:
- 缩点后是一个DAG图,那么是明星的点一定不会向其他点连边。 那么就可以判断每个点的出度是否为0,并统计是否只有一个点出度为0.
#include<cstdio>
#include<iostream>
#include<vector>
#include<queue>
using namespace std;
const int MAXN=1000010,MAXM=1000010;
struct first_Edge{
int from,to,nxt;
}first_e[MAXM];
int first_head[MAXN],first_edgeCnt=1;
void addFirstEdge(int u,int v){
first_e[++first_edgeCnt].from=u;
first_e[first_edgeCnt].to=v;
first_e[first_edgeCnt].nxt=first_head[u];
first_head[u]=first_edgeCnt;
}
int dfn[MAXN],dfnCnt=0,low[MAXN];
bool inc[MAXN];
int stck[MAXN],top=0;
vector<int> scc[MAXN];
int sccCnt=0,c[MAXN],siz[MAXN];
void tarjan(int x){
low[x]=dfn[x]=++dfnCnt;
stck[++top]=x;
inc[x]=1;
for(int i=first_head[x];i;i=first_e[i].nxt){
int v=first_e[i].to;
if(!dfn[v]){
tarjan(v);
low[x]=min(low[x],low[v]);
}else if(inc[v])low[x]=min(low[x],dfn[v]);
}
if(low[x]==dfn[x]){
int y;sccCnt++;
do{
y=stck[top--];
inc[y]=0;
scc[sccCnt].push_back(y);
c[y]=sccCnt;
siz[sccCnt]+=1;
}while(x!=y);
}
}
struct second_Edge{
int from,to,nxt;
}second_e[MAXM];
int second_head[MAXN],second_edgeCnt=0;
void addSecondEdge(int u,int v){
second_e[++second_edgeCnt].from=u;
second_e[second_edgeCnt].to=v;
second_e[second_edgeCnt].nxt=second_head[u];
second_head[u]=second_edgeCnt;
}
int cd[MAXN];
void rebuild(){
for(int i=1;i<=first_edgeCnt;i++){
int nowU,nowV;
nowU=first_e[i].from,nowV=first_e[i].to;
if(c[nowU]!=c[nowV]){
addSecondEdge(c[nowU],c[nowV]);
cd[c[nowU]]++;
}
}
}
int main(){
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
int a,b;
scanf("%d%d",&a,&b);
addFirstEdge(a,b);
}
for(int i=1;i<=n;i++)
if(!dfn[i])tarjan(i);
rebuild();
int ans=0;
bool isHave=0;
for(int i=1;i<=sccCnt;i++){
if(!cd[i]){
ans=scc[i].size();
if(isHave){
cout<<0<<endl;
return 0;
}
isHave=1;
}
}
cout<<ans<<endl;
return 0;
}