Popular Cows(POJ2186)

题目

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.

题意: 在一群N(1 <= N <= 10,000)奶牛中,你被给予M(1 <= M <= 50,000)有序对形式(A,B),告诉你牛A认为那头牛 B很受欢迎。 由于流行度是传递性的,如果A认为B很受欢迎并且B认为C很受欢迎,那么A也会认为C很流行,即使输入中没有明确指定C对。 你的任务是计算被其他每头牛认为都很受欢迎的奶牛数量。

思路:其实也算强连通分量的一个应用啦~当然,大部分人第一眼,就很想用Floyd算法来做,然是数据比较大,明显会超时啦
这里我们先用强连通分量处理一下,将所有牛分成不同的块,每一块内部都是互相欢迎的(只有一个牛也算自我欣赏),然后我们要得到受到其它每头牛的欢迎的奶牛数量,我们先将这些块当成每个点,DAG判断出度(很好判断,只需要判断每个点出边的块是否相等,如果不等,说明有出度),并且统计每个块的奶牛数量。再来分析什么样的牛是受到其它所有牛的欢迎的,当然是出度为0的嘛,并且这个出度为0的只能为1个,因为要受到所有牛的欢迎,那么所有的点都可以到达这个点,如果中间有的点不能,那么出度为0的也不为1个了(自己想想,建一个图,出度,入度啥的,这道题就是考虑出度,上道题是入度~)

代码如下:(有注释哦~(。・∀・)ノ)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int mx=1e5+10;
struct Edge{//链式前向星存边
   int to,next;
}e[mx];
int head[mx],tot;
int belong[mx],dfn[mx],low[mx];//块,查询i的顺序,i能到达的最小序号
int scc,Time,top;//块的数量,时间,栈顶
int Stack[mx],instack[mx];//模拟栈,是否入栈
int out[mx],cot[mx];//每个块的出度,每个块的数据数量
void add(int u,int v)//加边操作
{
	e[tot].to=v;
	e[tot].next=head[u];
	head[u]=tot++;
}
void Tarjan(int u){//tarjan算法
	dfn[u]=low[u]=++Time;
	Stack[top++]=u;
	instack[u]=1;
	for(int i=head[u];~i;i=e[i].next)
	{
		int v=e[i].to;
		if(!dfn[v])
		{
			Tarjan(v);
			low[u]=min(low[u],low[v]);
		}
		else if(instack[v])
		low[u]=min(low[u],dfn[v]);
	}
	if(dfn[u]==low[u])
	{
	   scc++;
	   int v;
	   do{
	   v=Stack[--top];
	   instack[v]=0;
	   belong[v]=scc;
       }while(v!=u);
   }
}

void init()//初始化嘛
{
	memset(dfn,0,sizeof(dfn));
	memset(low,0,sizeof(low));
	memset(head,-1,sizeof(head));
	memset(instack,0,sizeof(instack));
	memset(cot,0,sizeof(cot));
	tot=Time=scc=top=0;
}

int main()
{
	init();
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)
	{
		int u,v;
		scanf("%d%d",&u,&v);
		add(u,v);//加边
	}
	for(int i=1;i<=n;i++)//tarjan算法处理
	if(!dfn[i])Tarjan(i);
	
	for(int u=1;u<=n;u++)//查询所有的边,得到块的出度和块的元素个数
	{
		for(int i=head[u];~i;i=e[i].next)
		{
			int v=e[i].to;
			if(belong[u]!=belong[v])//如果出边和自身的块不一样
			{
				out[belong[u]]++;//出度加1
			}
		}
		cot[belong[u]]++;
	}
	int ss=0,ans;//统计出度为0的数量和结果
	for(int i=1;i<=scc;i++)
	{
		if(out[i]==0)//如果出度为0
		{
			ss++;
			ans=cot[i];
		}
	}
	if(ss!=1)
	printf("0\n");
	else
	printf("%d\n",ans);//输出结果啦
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值