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;
}