洛谷P2341 [HAOI2006]受欢迎的牛

本文介绍了一种基于有向图的强连通分量算法,用于解决明星奶牛评选问题。通过分析奶牛间的爱慕关系,利用深度优先搜索确定强连通分量,最终找出能被所有奶牛遍历到的明星奶牛数量。

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

题目描述

每头奶牛都梦想成为牛棚里的明星。被所有奶牛喜欢的奶牛就是一头明星奶牛。所有奶

牛都是自恋狂,每头奶牛总是喜欢自己的。奶牛之间的“喜欢”是可以传递的——如果A喜

欢B,B喜欢C,那么A也喜欢C。牛栏里共有N 头奶牛,给定一些奶牛之间的爱慕关系,请你

算出有多少头奶牛可以当明星。

输入输出格式

输入格式:

 第一行:两个用空格分开的整数:N和M

 第二行到第M + 1行:每行两个用空格分开的整数:A和B,表示A喜欢B

输出格式:

 第一行:单独一个整数,表示明星奶牛的数量

输入输出样例

输入样例#1: 
3 3
1 2
2 1
2 3
输出样例#1: 
1

说明

只有 3 号奶牛可以做明星

【数据范围】

10%的数据N<=20, M<=50

30%的数据N<=1000,M<=20000

70%的数据N<=5000,M<=50000

100%的数据N<=10000,M<=50000

强连通分量裸题。。。

在有向图中,如果有且仅有一个点的出度为0 (没有指向其他点的边),那么该点可以被所有点遍历到;反之,该图中没有可以被所有点遍历到的点;

在有向图中,如果一个点可以被所有点遍历到,那么这个点的出度为0

附代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#define MAXN 10010
#define MAXM 50010
using namespace std;
int n,m,c=1,d=1,top=1,s=0,ans=0;
int cstack[MAXN],head[MAXN],deep[MAXN],low[MAXN],colour[MAXN],num[MAXN],sum[MAXN];
bool beque[MAXN];
struct node{
	int next,to;
}a[MAXM<<1];
inline int read(){
	int date=0,w=1;char c=0;
	while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
	while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
	return date*w;
}
inline void add(int x,int y){
	a[c].to=y;
	a[c].next=head[x];
	head[x]=c++;
}
void work(int x){
	deep[x]=low[x]=d++;
	beque[x]=true;
	cstack[top++]=x;
	for(int i=head[x];i;i=a[i].next){
		int t=a[i].to;
		if(!deep[t]){
			work(t);
			low[x]=min(low[x],low[t]);
		}
		else if(beque[t])
		low[x]=min(low[x],deep[t]);
	}
	if(low[x]>=deep[x]){
		s++;
		do{
			beque[cstack[top-1]]=false;
			colour[cstack[top-1]]=s;
		}while(cstack[--top]!=x);
	}
}
int main(){
	int x,y;
	n=read();m=read();
	memset(num,0,sizeof(num));
	memset(sum,0,sizeof(sum));
	for(int i=1;i<=m;i++){
		x=read();y=read();
		add(x,y);
	}
	for(int i=1;i<=n;i++)if(!deep[i])work(i);
	for(int i=1;i<=n;i++)num[colour[i]]++;
	for(int i=1;i<=n;i++)
	for(int j=head[i];j;j=a[j].next){
		int t=a[j].to;
		if(colour[t]!=colour[i])sum[colour[i]]++;
	}
	for(int i=1;i<=s;i++)
	if(!sum[i]){
		if(ans){ans=0;break;}
		ans=i;
	}
	printf("%d\n",num[ans]);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值