Every cow’s dream is to become the most popular cow in the herd. In a herd of N (1 <= N <= 10,000) cows, you are given up to M (1 <= M <= 50,000) ordered pairs of the form (A, B) that tell you that cow A thinks that cow B is popular. Since popularity is transitive, if A thinks B is popular and B thinks C is popular, then A will also think that C is
popular, even if this is not explicitly specified by an ordered pair in the input. Your task is to compute the number of cows that are considered popular by every other cow.
Input
-
Line 1: Two space-separated integers, N and M
-
Lines 2…1+M: Two space-separated numbers A and B, meaning that A thinks B is popular.
Output -
Line 1: A single integer that is the number of cows who are considered popular by every other cow.
Sample Input
3 3
1 2
2 1
2 3
Sample Output
1
Hint
Cow 3 is the only cow of high popularity.
题意: 每一头牛的愿望就是变成一头最受欢迎的牛。现在有N头牛,给你M对整数(A,B),表示牛A认为牛B受欢迎。 这
种关系是具有传递性的,如果A认为B受欢迎,B认为C受欢迎,那么牛A也认为牛C受欢迎。你的任务是求出有多少头
牛被所有的牛认为是受欢迎的。
思路: 根据求有多少头牛被所有的牛认为是受欢迎的,我们可以想求强连通分量,缩点之后求出一个没有出度的点,然后将该点内部的点计数就是答案。代码实现主要内容讲解在注释里。
知识储备: 强连通分量是什么。缩点的含义是什么,为了什么。targan算法的实现原理。
#include <string.h>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <deque>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <list>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <stdexcept>
#include <string>
#include <vector>
using namespace std;
typedef unsigned long long ull;
#define ll long long
#define int long long
const int maxn = 2e5 + 100;
const int inf = 0x3f3f3f3f;
const int Base = 131;
const ll INF = 1ll << 62;
// const double PI = acos(-1);
const double eps = 1e-7;
const int mod = 1e9 + 7;
#define mem(a, b) memset(a, b, sizeof(a))
#define speed \
{ \
ios::sync_with_stdio(false); \
cin.tie(0); \
cout.tie(0); \
}
inline ll gcd(ll a, ll b) { return b == 0 ? a : gcd(b, a % b); }
int n, m, deep, cnt;
int low[maxn], dfn[maxn], countx[maxn], color[maxn], out[maxn];
int isInStack[maxn];
vector<int>e[maxn];
stack<int>st;//栈操作便于返回同一强连通分量的点
void dfs(int u){//targan算法求low序和dfn序
low[u] = dfn[u] = ++deep;
st.push(u);
isInStack[u] = 1;//标记是否在栈中
for(int i = 0; i < e[u].size(); i++){
int v = e[u][i];
if(!dfn[v]){
dfs(v);
low[u] = min(low[u], low[v]);
}
else if(isInStack[v]){
low[u] = min(low[u], dfn[v]);
}
}
if(low[u] == dfn[u]){
cnt++;
int top;
isInStack[u] = 0;
color[u] = cnt;//染色
do{
top = st.top();
color[top] = cnt;
isInStack[top] = 0;
st.pop();
}while(u != top);
}
}
int targan(int x){
cnt = deep = 0;
while(!st.empty())st.pop();
for(int i = 0; i < x; i++){
low[i] = 0;//最近祖先
dfn[i] = 0;//dfs序
isInStack[i] = 0;//是否在栈中
countx[i] = 0;//统计同一强连通分量中的点数
color[i] = 0;//染色
out[i] = 0;//统计缩点后该点的出度
}
for(int i = 0; i < n; i++){
if(!dfn[i]){
dfs(i);
}
}
return cnt;
}
signed main(){
scanf("%lld", &n);
scanf("%lld", &m);
for(int i = 0; i < m; i++){
int u, v;
scanf("%lld %lld", &u, &v);
e[u - 1].push_back(v - 1);
}
int tot = targan(n);//返回强连通分量数量
for(int i = 0; i < n; i++){
//一条边u->v,若u的颜色和v不同那么说明这两个点分别在两个强连通分量里面,
//且u所在的缩点有到v所咋的缩点的单向路径
countx[color[i]]++;
for(int j = 0; j < e[i].size(); j++){
if(color[i] != color[e[i][j]]){
out[color[i]]++;//统计缩点后的点出度
}
}
}
int flag = 0, p = -1;
for(int i = 1; i <= cnt; i++){//判断是否只有一个缩点的出度为0
if(out[i] == 0){
flag++;
if(flag == 2)break;
p = i;
}
}
if(flag == 1)printf("%lld\n", countx[p]);//输出该缩点内部点的数量
else printf("0\n");
system("pause");
return 0;
}