poj 2168--------Popular Cows(tarjan+缩点)

这道题 关于tarjan的地方我不想多说 只想讲一讲缩点的地方


其实我是不知道缩点是什么的 只是听说叫这个名字 但是我觉得这个名字好难听(逃

我们想 一头牛 要受其他所有牛的欢迎 那么这个牛所在的强连通分量中 不允许其中的任意一个点的相连的点 和这个点不在一个强连通分量中 因为如果不在一个强连通分量中 说明那个相连的点不能欢迎第一个强连通分量的祖先(根)

(我们把这个称为 强连通分量的出度)

这道题 在我们dfs的过程中 每次出栈的过程中 


(就是在这一坨里)

注意id数组 存储的是每个点所属的强连通分量的编号

(下面这张图我把id换成了 belong)


注意最后的判断 如果整个图里 有几个出度都为0的强连通分量 说明肯定没有一个牛可以被所有牛欢迎(如图)

如果只有一个出度为0的强连通分量 那就说明 肯定有一个牛被所有牛欢迎

附代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;

inline int read()
{
	int i=0;char c;bool z=false;
	while(isspace(c=getchar()));
	if(c=='-')	z=true,c=getchar();
	while(isdigit(c)) i=i*10+c-'0',c=getchar();
	if(!z)	return i;
	else return -i;
}

int n,m,tot,sign,top,sum;
int to[50005],first[10005],next[50005]; 
int dfn[10005],low[10005];
int sta[10005];
int belong[10005];
bool insta[10005];

int out[10005];
int num[10005];
void add(int x,int y)
{
	tot++;
	next[tot]=first[x];
	to[tot]=y;
	first[x]=tot;
}

void dfs(int x)
{
	int i;
	sign++;
	dfn[x]=sign,low[x]=sign;
	sta[++top]=x;
	insta[x]=true;
	int k=first[x];
	while(k!=0)
	{
		i=to[k];
		if(dfn[i]==0)
		{
			dfs(i);
			if(low[i]<low[x])	low[x]=low[i];
		}
		else
		{
			if(insta[i]==true&&dfn[i]<low[x])	low[x]=dfn[i];
		}
		k=next[k];
	}
	
	if(low[x]==dfn[x])
	{
		sum++;
		i=sta[top];
		while(i!=x)
		{
			belong[i]=sum;
			insta[i]=false;
			top--;
			i=sta[top];
		}
		top--;
		insta[top]=false;
		belong[i]=sum;
	}
} 
int main()
{
	while(cin>>n>>m)
	{
	
	for(int i=1;i<=m;i++)
	{
		int x,y;
		x=read();
		y=read();
		add(x,y);		
	}
	for(int i=1;i<=n;i++)
	{
		if(dfn[i]==0) dfs(i);
	}
	
	
	for(int i=1;i<=n;i++)
	{
		int tmp=belong[i];
		num[tmp]++;
		for(int j=first[i];j;j=next[j])
		{
			int en=to[j];
			if(belong[i]!=belong[en])
			{
				out[tmp]++;
			}
		}
	}
	
	int ans=0,true_ans;
	for(int i=1;i<=sum;i++)
	{
		if(out[i]==0)
		{
			ans++;
			true_ans=i;
		}	
	}
	if(ans>1)	cout<<"0"<<endl;
	else cout<<num[ans]<<endl;
	}
	return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值