动态规划(6)Popular Cows poj2186

本文深入探讨了一道计算机科学竞赛题目,旨在找出在牛群中唯一受到所有牛崇拜的个体。通过使用深搜和强连通分量的概念,作者详细解释了解决该问题的方法和背后的算法原理,提供了清晰的代码实现步骤和实例分析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Popular Cows
Time Limit: 2000MS Memory Limit: 65536K
Total Submissions: 18989 Accepted: 7623

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

 
 
题意是求出受全部牛崇拜的的牛的个数,而不是最受欢迎的牛的个数(WA了好多次。。)
这一题用的是深搜+强连通分量,用Tarjan算法只用一次DFS,也可以用korasaju算法求。
Tarjan:
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<stdlib.h>
using namespace std;
#define N 10005
#define M 50005
struct node
{
	int u,v,next;//u:边的起始点;v:边的终点。next:以u为起点的下一条边的编号
}edge[M];
int outd[N];
int low[N],dfn[N],scc,belong[N];
bool ins[N];
//dfn[i]表示编号为i的节点在DFS过程中的访问时间(开始时间);
//low[i]表示从i节点出发DFS过程中i的下方节点(开始时间大于dfn[i],且由i可达的节点)所能到达的最早的节点的开始时间。
//初始时low[i] = dfn[i];
//ins[i]表示i是否在栈中,1表示在,0表示不在。
//belong染色,分强连通分量。scc,表示第几个强连通分量。
int stack[N],top,index,n,m,e,head[N];//head[x]是指以x为起点的最后一条边的编号,初始化为-1.
bool vis[N];//是否被访问。

void init()
{
	top = index = e = scc = 0; 
    memset(dfn, 0, sizeof(dfn));  
	//memset(low, 0, sizeof(low)); 
	memset(vis, false, sizeof(vis));  
    memset(ins, false, sizeof(ins));  
    memset(outd, 0, sizeof(outd));  
	memset(head, -1, sizeof(head));  
}
void addedge(int u,int v)//加边,邻接表
{
	edge[e].u = u;
	edge[e].v = v;
	edge[e].next = head[u];
	head[u] = e++;
}
void dfs(int u)
{
	int v;
	dfn[u] = low[u] = ++index; 
	stack[top++] = u;//入栈
	vis[u] = true;
	ins[u] = 1;
	for(int i=head[u];i!=-1;i = edge[i].next)//遍历边
	{			  
		v = edge[i].v;
		if(!dfn[v] && !vis[v])
		{
		     dfs(v);
		     low[u] = min(low[u],low[v]);//如果u 的子节点能够到达更早的时间,那么u一定也能。
		}
		else if(ins[v])
		{
		     low[u] = min(low[u],dfn[v]);//如果已经在栈里,就取子节点的发现时间和u的low值较小值。
		}
	}
	if(dfn[u] == low[u])//找到了一个强连通分量。
	{
		++scc;
		do{
			v = stack[--top];
			stack[top] = 0;//退栈。
			ins[v] = 0;
			belong[v] = scc;
		}while(u!=v);
	}
}
void Tarjan()
{
	for(int i=0;i<m;i++)
	{
		if(!dfn[edge[i].u])
		dfs(edge[i].u);
	}
}
void countoutdeg()//求强连通分量缩点后的出度
{
	for (int u=1; u<=n; ++u) 
        for (int i=head[u]; i!=-1; i=edge[i].next)
        {
            int v = edge[i].v;
            if (belong[u] != belong[v])
            {              
                outd[belong[u]]++;
            }
        }
}
int main()
{
	int i,u,v,x;
	while(~scanf("%d %d",&n,&m)){
	init();
	for(i = 1;i<=m;i++)
	{
			scanf("%d %d",&u,&v);
			addedge(u,v);
	}
	Tarjan();
	countoutdeg();
	int count=0;
	for(i=1;i<=scc;i++)
		if(outd[i]==0) 
			{
				++count;
		        x=i;
		}
	for(i=1;i<=n;i++)
		if(!vis[i]) count++;//确保求的是被所有的牛所欢迎的
	if(count > 1)  printf("0\n");
	else
	{
		count = 0;
		for(i=1;i<=n;i++)
			if(belong[i] == x)//出度为0的强连通分量只能有一个,否则就输出0了,所以x是唯一的。
				++count;
	printf("%d\n",count); 
	}
	}
//	system("pause");
	return 0;
}

 
 
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值