#include <iostream>
#include <cstdio>
#include <cstring>
#include <stack>
#define debug puts("here")
using namespace std;
const int M = 10009;
const int N = 50009;
struct node
{
int v;
int next;
}num[N];
int sccf[M];
int low[M];
int dfn[M];
bool ins[M];
int adj[M];
int rdu[M];
int scc, index;
stack<int>s;
int n, m;
void init() {
scc = 0;
index = 1;
memset(dfn, 0, sizeof(dfn));
memset(low, 0, sizeof(low));
memset(adj, -1, sizeof(adj));
memset(ins, false, sizeof(ins));
memset(sccf, 0, sizeof(sccf));
}
void Tarjan(int u) {
int v;
low[u] = dfn[u] = index++;
s.push(u);
ins[u] = true;
for(int k = adj[u]; k != -1; k = num[k].next) {
v = num[k].v;
if(dfn[v] == 0) {
Tarjan(v);
if(low[v] < low[u]) {
low[u] = low[v];
}
}
else if(ins[v]&& low[v] < low[u]) {
low[u] = low[v];
}
}
if(low[u] == dfn[u])
{
scc++;
do
{
v = s.top();
s.pop();
ins[v] = false;
sccf[v] = scc;//此步进行所谓的缩点;
}while(u != v);
}
}
int getsuperpopularnum() {
memset(rdu, 0, sizeof(rdu));
int v, u;
int cnt = 0;
int cn[N];
memset(cn, 0, sizeof(cn));
for(u = 1; u <= n; u++) {
cn[sccf[u]]++; //同一缩点内的点数;
for(int k = adj[u]; k != -1; k = num[k].next)
{
v = num[k].v;
if(sccf[v] != sccf[u])
{
rdu[sccf[u]]++;
}
}
}
for(int i = 1; i <= scc; i++)
{
if(rdu[i] == 0)
{
cnt++;
v = i;
}
}
return (cnt == 1)? cn[v] : 0;//如果出度为零的点多以一个, 则无解;
}
int main()
{
int a, b;
int e = 0;
init();
cin>>n>>m;
for(int i = 1; i <= m; i++) {
cin>>a>>b;
num[e].v = b; //通过e 找到a 的下一个边b;
num[e].next = adj[a];//存a可到达的下一个边;
adj[a] = e;//通过adj[a]找到节点e
e++;
}
for(int i = 1; i <= n; i++)
{
if(dfn[i] == 0)
{
Tarjan(i);
}
}
printf("%d\n", getsuperpopularnum());
return 0;
}
详细资料 :https://www.byvoid.com/blog/scc-tarjan