题目来源:http://poj.org/problem?id=2186
思路:先处理出所有的强连通分量,将所有的强连通分量染色,缩点,这样原图变成了一棵有向树。如果出度为0的节点有且仅有一个,则这个节点所对应的强连通分量就是所有满足题意的节点。
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <iostream>
#define ll long long
using namespace std;
const int maxn = 1e4 + 10;
int n, m, cnt, top, cur, color, head[maxn], du[maxn], dfn[maxn], low[maxn], s[maxn], g[maxn], num[maxn];
bool vis[maxn];
struct data {
int to, next;
} e[maxn * 5];
void ins(int x, int y) {
e[++cnt].to = y;
e[cnt].next = head[x];
head[x] = cnt;
}
void tarjan(int u) {
low[u] = dfn[u] = ++cur;
vis[u] = 1;
s[++top] = u;
for (int i = head[u]; i; i = e[i].next) {
int x = e[i].to;
if (dfn[x] == 0)tarjan(x);
if (vis[x] && low[u] > low[x])low[u] = low[x];
}
if (dfn[u] == low[u]) {
++color;
while (s[top + 1] != u) {
g[s[top]] = color;
vis[s[top]] = 0;
num[color]++;
top--;
}
}
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
while (cin >> n >> m) {
int x, y;
cnt = cur = top = color = 0;
memset(head, 0, sizeof(head));
for (int i = 1; i <= m; ++i) {
cin >> x >> y;
ins(x, y);
}
memset(vis, 0, sizeof(vis));
memset(s, 0, sizeof(s));
memset(du, 0, sizeof(du));
memset(dfn, 0, sizeof(dfn));
memset(low, 0, sizeof(low));
memset(num,0,sizeof(num));
for (int i = 1; i <= n; ++i) {
if (dfn[i] == 0) {
tarjan(i);
}
}
for (int i = 1; i <= n; ++i) {
for (int j = head[i]; j; j = e[j].next) {
if (g[i] != g[e[j].to]) {
du[g[i]]++;
}
}
}
bool ok=1;
int ans = 0;
for (int i = 1; i <= color; ++i) {
if (du[i] == 0) {
if (ans == 0)
ans = num[i];
else {
ok = 0;
break;
}
}
}
if (ok) cout << ans << endl;
else cout << 0 << endl;
}
return 0;
}