题目地址


简述:

  • 缩点+判定(性质)

易错点:

  • 缩点后是一个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;
}