1. 程式人生 > >LOJ #10091. 「一本通 3.5 例 1」受歡迎的牛

LOJ #10091. 「一本通 3.5 例 1」受歡迎的牛

https://loj.ac/problem/10091

題目描述

原題來自:USACO 2003 Fall

每一頭牛的願望就是變成一頭最受歡迎的牛。現在有 NNN 頭牛,給你 MMM 對整數 (A,B)(A,B)(A,B),表示牛 AAA 認為牛 BBB 受歡迎。這種關係是具有傳遞性的,如果 AAA 認為 BBB 受歡迎,BBB 認為 CCC 受歡迎,那麼牛 AAA 也認為牛 CCC 受歡迎。你的任務是求出有多少頭牛被除自己之外的所有牛認為是受歡迎的。

輸入格式

第一行兩個數 N,MN,MN,M;
接下來 MMM 行,每行兩個數 A,BA,BA,B,意思是 AAA 認為 BBB 是受歡迎的(給出的資訊有可能重複,即有可能出現多個 A,BA,BA,B)。

輸出格式

輸出被除自己之外的所有牛認為是受歡迎的牛的數量。

樣例

樣例輸入

3 3
1 2
2 1
2 3

樣例輸出

1

樣例說明

只有第三頭牛被除自己之外的所有牛認為是受歡迎的。

資料範圍與提示

對於全部資料,1≤N≤104,1≤M≤5×1041\le N\le 10^4,1\le M\le 5\times 10^41≤N≤104,1≤M≤5×104。

 

當這是一棵樹的時候,很容易看出求每個點的出度,輸出是否存在出度為0的點

(如果有多個結點,是不可能有奶牛被其餘牛都歡迎,答案為0)

但這是一個有向圖,所以要縮點後進行如上的操作

#include<cstdio>
#include<iostream>
using namespace std;
int read()
{
	int ret=0;
	char ch=getchar();
	while(ch<'0'||ch>'9') ch=getchar();
	while(ch>='0'&&ch<='9')
		ret=(ret<<1)+(ret<<3)+ch-'0',ch=getchar();
	return ret;
}

const int N=1e6+4;
int n,m,a[N],d[N],ans;
int he[N],to[N],nxt[N],cnt;
int dfn[N],sgn,low[N],st[N],top,co[N],col;
struct NA{
	int u,v;
}e[N];

inline void add(int u,int v)
{
	to[++cnt]=v;
	nxt[cnt]=he[u];
	he[u]=cnt;
}

void Tarjan(int u)
{
	dfn[u]=low[u]=++sgn;
	st[++top]=u;
	for(int e=he[u];e;e=nxt[e])
	{
		int v=to[e];
		if(!dfn[v]) 
			Tarjan(v),low[u]=min(low[u],low[v]);
			else if(!co[v]) 
				low[u]=min(low[u],dfn[v]); 	
	}	
	if(dfn[u]==low[u])
	{
		co[u]=++col;
		while(top&&st[top]!=u)
			co[st[top--]]=col;
		top--;
	}
}

int main()
{
	n=read(),m=read();
	for(int i=1;i<=m;i++)
		e[i].u=read(),e[i].v=read(),
		add(e[i].u,e[i].v);
	for(int i=1;i<=n;i++)
		if(!dfn[i]) Tarjan(i);
	for(int i=1;i<=n;i++)
		a[co[i]]++;
	for(int i=1;i<=m;i++)
		if(co[e[i].v]!=co[e[i].u])
			d[co[e[i].u]]++;
	for(int i=1;i<=col;i++)
		if(!d[i])
		{
			if(!ans) ans=a[i];
				else 
				{
					ans=0; break;
				}
		}
	printf("%d\n",ans);
}