[HAOI2006]受欢迎的牛

题目

bzoj1051

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath> 
#define N 100100
using namespace std; 

int n,m,ans;
int dfn[N],t;//每一个节点被访问的时间戳,即dfs序 
int low[N];//low[i]所能回溯到的最早的节点的dfn值
bool flag[N];//标记栈中的点 
int stack[N],top;//栈,存放已经访问过的点 
int be[N];//记录每个强连通分量 
bool mark[N]; 

int a[N],b[N],p[N],nt[N],num;
void add(int x,int y)
{
	a[++num]=x;b[num]=y;
	nt[num]=p[x];p[x]=num;
}

int cnt;
int tarjan(int x)//当前访问节点 
{
	dfn[x]=low[x]=++t;
	stack[++top]=x;
	flag[x]=1;
	for(int e=p[x];e;e=nt[e])
	{
		int k=b[e];
		if(!dfn[k])
		{
			tarjan(k);
			low[x]=min(low[x],low[k]);
		}
		else if(flag[k]) low[x]=min(low[x],dfn[k]);
	}
	if(low[x]==dfn[x])//若找到请联通分量,将其全部弹出 
	{
		cnt++;
		while(flag[x])
		{
			int k=stack[top--];
			flag[k]=0;
			be[k]=cnt;
		}
	}
}

int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)
	{
		int x,y;scanf("%d%d",&x,&y);add(x,y);
	}
	for(int i=1;i<=n;i++)
		if(!dfn[i]) tarjan(i);
	for(int i=1;i<=m;i++)
	{
		if(be[a[i]]!=be[b[i]])//如果当前点能到达另一个强连通分量 
		mark[be[a[i]]]=1;//当前点所处的强连通分量显然不满足题意 
	}
	int sum=0,pos;//记录出度为0的强连通分量个数与位置 
	for(int i=1;i<=cnt;i++)
		if(!mark[i]) {sum++;pos=i;}
	if(sum!=1) {printf("0");return 0;}
	for(int i=1;i<=n;i++)
		if(be[i]==pos) ans++;
	printf("%d",ans);
	return 0;
}
posted @ 2017-09-30 15:32  XYZinc  阅读(140)  评论(0编辑  收藏  举报