POJ2186 Popular Cows 强联通求出度为零

题意:给出有向边,并且有向边可以传递,即A可以到B,B可以到C,则A可以到C

问有多少节点可以由其它除其本身的所有节点到达;

强联通转化:强联通缩点后,若出度为零的点不唯一,则无解,若唯一,求联通块的节点数,,,


#include<cstdio>
#include<stdlib.h>
#include<string.h>
#include<string>
#include<map>
#include<cmath>
#include<iostream>
#include <queue>
//#include <stack>
#include<algorithm>
#include<set>
using namespace std;
#define INF 1e8
#define eps 1e-8
#define LL __int64
#define maxn 26
#define mol 1000000007
#define N 10010
#define M 50010
struct Edge  
{  
	int v;  
	int next;  
};  
Edge edge[M];//边的集合  

int node[N];//顶点集合  
int instack[N];//标记是否在stack中  
int stack[N];  
int Belong[N];//各顶点属于哪个强连通分量  
int DFN[N];//节点u搜索的序号(时间戳)  
int LOW[N];//u或u的子树能够追溯到的最早的栈中节点的序号(时间戳)  
int n, m;//n:点的个数;m:边的条数  
int cnt_edge;//边的计数器  
int Index;//序号(时间戳)  
int top;  
int Bcnt;//有多少个强连通分量  
int in[N],out[N],numd[N];
void add_edge(int u, int v)//邻接表存储  
{  
	edge[cnt_edge].next = node[u];  
	edge[cnt_edge].v = v;  
	node[u] = cnt_edge++;  
}  
void tarjan(int u)  
{  
	int i, j;  
	int v;  
	DFN[u] = LOW[u] = ++Index;  
	instack[u] = true;  
	stack[++top] = u;  
	for (i = node[u]; i != -1; i = edge[i].next)  
	{  
		v = edge[i].v;  
		if (!DFN[v])//如果点v没被访问//树枝边  
		{  
			tarjan(v);  
			if (LOW[v]<LOW[u])  
				LOW[u] = LOW[v];  
		}  
		else//如果点v已经被访问过//后向边  
			if (instack[v] && DFN[v]<LOW[u])  
				LOW[u] = DFN[v];  
	}  
	if (DFN[u] == LOW[u])//缩点  
	{  
		Bcnt++;  
		do  
		{  
			j = stack[top--];  
			instack[j] = false;  
			Belong[j] = Bcnt;  
		} while (j != u);  
	}  
}  
void solve()  
{  
	int i;  
	top = Bcnt = Index = 0;  
	memset(DFN, 0, sizeof(DFN));  
	memset(LOW, 0, sizeof(LOW));  
	memset(Belong, 0, sizeof(Belong)); 
	for (i = 1; i <= n; i++)  
		if (!DFN[i])  
			tarjan(i);  
}  
int main()  
{  
	//freopen("in.txt", "r", stdin);  
	int i, j, k, t;  
	while(~scanf("%d %d", &n,&m))
	{
		cnt_edge = 0;  
		memset(node, -1, sizeof(node));  

		for (i = 1; i <= m; i++)  
		{  
			scanf("%d%d", &j,&k);
				add_edge(j,k);  
		}  
		solve();  
		memset(in,0,sizeof(in));
		memset(out,0,sizeof(out));
		memset(numd,0,sizeof(numd));
		for(i=1;i<=n;i++)
		{
			for(j=node[i];j!=-1;j=edge[j].next )
			{
				if(Belong[i]!=Belong[edge[j].v])
				{
					in[Belong[edge[j].v]]++;
					out[Belong[i]]++;
				}
			}
		}
		int a,b=0;
		for(i=1;i<=Bcnt;i++)
		{
			if(!out[i])
			{
				b++;
				a=i;
			}
		}
		if(b!=1) printf("0\n");
		else
		{
			int ans=0;
			for(i=1;i<=n;i++)
			{
				if(Belong[i]==a)
					ans++;
			}
			printf("%d\n",ans);
		}
	}
	return 0;  
}  
/*
3 3
1 2
2 1
2 3
*/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值