题目链接:http://poj.org/problem?id=2186。
思路:利用tarjan构造强连通分量,并统计各强连通分量内节点数目, 然后将各强连通分量当成一个节点对待,构成一个新的图,统计出各节点的出度数,要存在受其他牛欢迎的牛,那么强连通分量构成的图必定是一个连通的DAG,而且该DAG出度为0的节点数有且只有1个,否则是不存在满足题意的牛。代码实现如下:
#include <iostream>
#include <vector>
#include <stack>
using namespace std;
int n, m, a, b, clockCnt, sccCnt;
vector<vector<int> > graph;
vector<int> pre, lowlink, sccno, nodeCnt;
stack<int> s;
void init() {
clockCnt = 0;
sccCnt = 0;
graph.resize(n+1);
pre.resize(n+1, 0);
lowlink.resize(n+1, 0);
sccno.resize(n+1, 0);
nodeCnt.resize(n+1, 0);
while (!s.empty()) s.pop();
}
void tarjan(int v) {
pre[v] = lowlink[v] = ++clockCnt;
s.push(v);
for (int i = 0; i < graph[v].size(); i++) {
int u = graph[v][i];
if (!pre[u]) {
tarjan(u);
lowlink[v] = min(lowlink[v], lowlink[u]);
} else if (!sccno[u]) {//dedicate u is in stack
lowlink[v] = min(lowlink[v], pre[u]);
}
}
int u, cnt = 0;
if (lowlink[v] == pre[v]) {
sccCnt++;
do {
u = s.top(); s.pop();
cnt++;
sccno[u] = sccCnt;
} while (u != v);
nodeCnt[sccCnt] = cnt;
}
}
int main() {
cin >> n >> m;
init();
for (int i = 0; i < m; i++) {
cin >> a >> b;
graph[a].push_back(b);
}
for (int i = 1; i <= n; i++) {
if (!pre[i]) tarjan(i);
}
vector<int> out(sccCnt+1, 0);
for (int i = 1; i <= n; i++) {
for (int j = 0; j < graph[i].size(); j++) {
int x = sccno[graph[i][j]];
if (sccno[i] == x) continue;
out[sccno[i]]++;
}
}
int idx, cnt = 0;
for (int i = 1; i <= sccCnt; i++) {
if (!out[i]) {
cnt++;
idx = i;
}
}
if (cnt == 1) cout << nodeCnt[idx] << endl;
else cout << 0 << endl;
return 0;
}