1174. 受欢迎的牛

题目链接

1174. 受欢迎的牛

每一头牛的愿望就是变成一头最受欢迎的牛。

现在有 \(N\) 头牛,编号从 \(1\)\(N\),给你 \(M\) 对整数 \((A,B)\),表示牛 \(A\) 认为牛 \(B\) 受欢迎。

这种关系是具有传递性的,如果 \(A\) 认为 \(B\) 受欢迎,\(B\) 认为 \(C\) 受欢迎,那么牛 \(A\) 也认为牛 \(C\) 受欢迎。

你的任务是求出有多少头牛被除自己之外的所有牛认为是受欢迎的。

输入格式

第一行两个数 \(N,M\)

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

输出格式

输出被除自己之外的所有牛认为是受欢迎的牛的数量。

数据范围

\(1≤N≤10^4,\)
\(1≤M≤5×10^4\)

输入样例:

3 3
1 2
2 1
2 3

输出样例:

1

样例解释

只有第三头牛被除自己之外的所有牛认为是受欢迎的。

解题思路

缩点,有向图强联通分量,tarjan

联通分量:一个子图中的任意两个点互相可达
强连通分量:极大连通分量,即再增加其他点不再形成连通分量

\(dfs\) 遍历,一个点在强连通分量中只有两种情况:其后向边指向祖先节点,其横叉边指向的点通过后向边指向祖先节点

一个点为强连通分量的最高点等价于 \(dfn[x]=low[x]\)

利用 \(tarjan\) 算法可以将一个有向图转化为有向无环图(\(dag\)),而且由于 \(tarjan\) 算法是 \(dfs\) 序,得到的点也就满足拓扑序

本题将图缩点为 \(dag\) 后,判断出度为 \(0\) 的点有多少个,如果数量大于 \(1\),说明这两点互不可达,没有满足要求的答案的点,否则只有一个点,答案为该点的强连通分量的点数

  • 时间复杂度:\(O(n+m)\)

代码

// Problem: 受欢迎的牛
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/1176/
// Memory Limit: 64 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

// %%%Skyqwq
#include <bits/stdc++.h>
 
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
 
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
 
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
 
template <typename T> void inline read(T &x) {
    int f = 1; x = 0; char s = getchar();
    while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
    while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
    x *= f;
}

const int N=1e4+5;
int n,m;
vector<int> adj[N];
int dfn[N],low[N],timestamp,scc_cnt,stk[N],id[N],top,dout[N];
bool in_stk[N];
int res,sz[N];
void tarjan(int x)
{
	dfn[x]=low[x]=++timestamp;
	stk[++top]=x;
	in_stk[x]=true;
	for(int y:adj[x])
	{
		if(!dfn[y])
		{
			tarjan(y);
			low[x]=min(low[x],low[y]);
		}
		else if(in_stk[y])low[x]=min(low[x],dfn[y]);
	}
	if(low[x]==dfn[x])
	{
		int y;
		++scc_cnt;
		do
		{
			y=stk[top--];
			in_stk[y]=false;
			id[y]=scc_cnt;
			sz[scc_cnt]++;
		}while(y!=x);
	}
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
    	int a,b;
    	cin>>a>>b;
    	adj[a].pb(b);
    }
    for(int i=1;i<=n;i++)
    	if(!dfn[i])tarjan(i);
    for(int i=1;i<=n;i++)
    	for(int j:adj[i])
    		if(id[i]!=id[j])dout[id[i]]++;
    for(int i=1;i<=scc_cnt;i++)
    	if(!dout[i])
    	{
    		if(res)
    		{
    			res=0;
    			break;
    		}
    		res+=sz[i];
    	}
    cout<<res;
    return 0;
}
posted @ 2022-08-10 21:39  zyy2001  阅读(59)  评论(0编辑  收藏  举报