poj 2186 Popular Cows 强连通+缩点+邻接表

题目链接:http://poj.org/problem?id=2186

Popular Cows
Time Limit: 2000MS Memory Limit: 65536K
Total Submissions: 21572 Accepted: 8819

Description

Every cow's dream is to become the most popular cow in the herd. In a herd of N (1 <= N <= 10,000) cows, you are given up to M (1 <= M <= 50,000) ordered pairs of the form (A, B) that tell you that cow A thinks that cow B is popular. Since popularity is transitive, if A thinks B is popular and B thinks C is popular, then A will also think that C is
popular, even if this is not explicitly specified by an ordered pair in the input. Your task is to compute the number of cows that are considered popular by every other cow.

Input

* Line 1: Two space-separated integers, N and M

* Lines 2..1+M: Two space-separated numbers A and B, meaning that A thinks B is popular.

Output

* Line 1: A single integer that is the number of cows who are considered popular by every other cow.

Sample Input

3 3
1 2
2 1
2 3

Sample Output

1

Hint

Cow 3 is the only cow of high popularity.

Source

题目大意:

N头奶牛,给出若干个欢迎关系A B,表示A欢迎B,欢迎关系是单向的,但是是可以传递的。另外每个奶牛都是欢迎他自己的。求出被所有的奶牛欢迎的奶牛的数目。

奶牛数目N≤10000
直接的欢迎关系数目M≤50000

题解:

数据量太大,直接搞肯定行不通,如果A欢迎B,我们就连一条从A到B的有向边。容易发现,在同一个强连通分量里的点具有同样的“受欢迎程度”:能够到达它们的点集是相同的,从它们出发能够到达的点集也是相同的。所以我们把强连通缩点,最后扫描求出

出度为0的点个数,如果是1就说明这个顶点(也可能是收缩的点)即为所求答案,否则为0。

tarjan看了几天才大概看懂,。缩点参考的是http://www.myexception.cn/program/1449753.html这篇文章

有一个数组belong[MAX]来染色,belong[i] =scc 就表示 i 这个元素属于第scc个强连通分量,在把所有的点求完强连通分量之后,我们只是得到一个所有点的归属数组Belong[MAX],那么,之后我们就用两个数组 in[MAX],out[MAX]表示缩点后的有向无环图的点的入度和出度

具体代码如下:

/**
 * @author neko01
 */
//#pragma comment(linker, "/STACK:102400000,102400000")
#include <cstdio>
#include <cstring>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <math.h>
#include <queue>
using namespace std;
typedef long long LL;
#define INF 100000000
const double pi=acos(-1.0);
const double eqs=1e-10;
int head[10005];
int dfn[10005];
int low[10005];
int belong[10005]; //节点i属于哪个强连通
int num[10005];    //强连通i的节点数
int stack[10005];
int vis[10005];    //vis[i]=1表示在栈中
int out[10005];
int cnt,top,scc;
int n,m;
struct edge{
	int to;
	int next;
}a[50005];
void add(int u,int v)
{
	a[cnt].to=v;
	a[cnt].next=head[u];
	head[u]=cnt++;
}
void tarjan(int u)
{
	dfn[u]=low[u]=++cnt;
	stack[++top]=u;
	vis[u]=1;
	for(int i=head[u];i!=-1;i=a[i].next)
	{
		int v=a[i].to;
		if(!dfn[v])
		{
			tarjan(v);
			low[u]=min(low[u],low[v]);
		}
		else if(vis[v])       //回边
		{
			low[u]=min(low[u],dfn[v]);
		}
	}
	if(dfn[u]==low[u])   //根
	{
		scc++;
		int t;
		do
		{
			t=stack[top--];
			vis[t]=0;
			num[scc]++;
			belong[t]=scc;
		}while(u!=t);
	}
}
void solve()
{
	cnt=top=scc=0;
	for(int i=1;i<=n;i++)
	{
		if(!dfn[i])
			tarjan(i);
	}
	int ans=0,k=1;
	for(int i=1;i<=n;i++)
	{
		for(int j=head[i];j!=-1;j=a[j].next)
		{
			int v=a[j].to;
			if(belong[v]!=belong[i])
				out[belong[i]]++;
		}
	}
	for(int i=1;i<=scc;i++)
		if(out[i]==0)
			ans++,k=i;
	if(ans==1)
		printf("%d\n",num[k]);
	else
		printf("0\n");
}
int main()
{
	scanf("%d%d",&n,&m);
	memset(head,-1,sizeof(head));
	for(int i=1;i<=m;i++)
	{
		int u,v;
		scanf("%d%d",&u,&v);
		add(u,v);
	}
	solve();
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值