C++——tarjan模板

这是一篇关于利用C++编程解决POJ2186问题的博客。题目要求计算在传递性受欢迎关系中,有多少头牛被所有牛认为受欢迎。文章提供输入格式、输出格式及样例数据,并适用于处理规模为10000头牛和50000对关系的复杂情况。

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

题目背景

POJ2186

HAOI2006 DAY1 T3

题目描述

每一头牛的愿望就是变成一头最受欢迎的牛。现在有 N 头牛,给你 M 对整数(A,B),表示牛A认为牛B受欢迎。这种关系是具有传递性的,如果 A 认为 B 受欢迎,B 认为 C 受欢迎,那么牛A也认为牛C受欢迎。你的任务是求出有多少头牛被所有的牛认为是受欢迎的。

输入格式

第一行两个数 N,M 。
接下来 M 行,每行两个数 A,B,意思是 A 认为 B 是受欢迎的(给出的信息有可能重复,即有可能出现多个 A,B)

输出格式

输出一个整数,即有多少头牛被所有的牛认为是受欢迎的。如果没有满足这种条件的情况,输出“0”。

样例数据 1

输入

3 3 
1 2 
2 1 
2 3

输出

1

备注

【样例说明】
只有牛 3 是受到所有牛欢迎的。

【数据范围】
10% 的数据:N≤20;M≤50
30% 的数据:N≤1000;M≤20000
70% 的数据:N≤5000;M≤50000
100% 的数据:N≤10000;M≤50000

#include<bits/stdc++.h>
#define MAXE 100050
#define MAXV 500050
using namespace std;
struct edge{
int u,v,next;
}edges[MAXE];
int n,m,ncount=0;
int head[MAXV],low[MAXV],dfn[MAXV],belong[MAXV],stack[MAXV],num[MAXV],out[MAXV];
int tot=0,cnt=0,top=0;
bool visit[MAXV];
int readint()
{
    int i=0,f=1;
    char ch;
    for(ch=getchar();(ch<'0'||ch>'9') && ch!='-';ch=getchar());
    if(ch=='-')
    {
        f=-1; 
        ch=getchar();
    }
    for(;ch>='0' && ch<='9';ch=getchar())
        i=(i<<3)+(i<<1)+ch-'0';
    return i*f;
}
void add(int u,int v)
{
	edges[++ncount].u=u;
	edges[ncount].v=v;
	edges[ncount].next=head[u];
	head[u]=ncount;
}
void tarjan(int u)
{
	low[u]=dfn[u]=++cnt;
	stack[++top]=u;
	visit[u]=true;
	for(int p=head[u];p!=-1;p=edges[p].next)
	{
		int v=edges[p].v;
		if(!dfn[v])
		{
			tarjan(v);
			low[u]=min(low[u],low[v]);
		}
		else if(visit[v])
		low[u]=min(low[u],dfn[v]);
	}
	if(dfn[u]==low[u])
	{
		tot++;
		int v=-1;
		while(u!=v)
		{
		v=stack[top--];
		belong[v]=tot;
		num[tot]++;
		visit[v]=false;
		}
	}
}
int main()
{
	memset(head,-1,sizeof(head));
	n=readint();
	m=readint();
	for(int i=1;i<=m;i++)
	{
		int u,v;
		u=readint();
		v=readint();
		add(u,v);
	}
	for(int i=1;i<=n;i++)
		if(!dfn[i])
			tarjan(i);
	for(int i=1;i<=m;i++)
		if(belong[edges[i].u]!=belong[edges[i].v]) out[belong[edges[i].u]]++;
	int ans,res=0;
	for(int i=1;i<=tot;i++)
		if(out[i]==0)
		{
			res++;
			ans=i;
		}
	if(res==1) printf("%d\n",num[ans]);
	else printf("0\n");
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值