题意
题解
T a r j a n Tarjan Tarjan 求解 S C C SCC SCC,考虑缩点后得到的 D A G DAG DAG。满足条件的节点一定在 D A G DAG DAG 唯一的出度为 0 0 0 的 S C C SCC SCC,即自底而上求的最小拓扑序的 S C C SCC SCC 中,构造反图,判断这个 S C C SCC SCC 中的某个节点是否可以遍历所有的点即可。这种判断方法可以从任意起点仅用一次 T a r j a n Tarjan Tarjan。总时间复杂度 O ( N + M ) O(N+M) O(N+M)。
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 10005, maxm = 50005;
int N, M, num, dfn[maxn], low[maxn];
int top, st[maxn], scc, sc[maxn];
int tot, head[maxn], to[maxm], nxt[maxm];
int tot_r, hr[maxn], tr[maxm], nr[maxm];
bool in[maxn], vs[maxn];
inline void add(int x, int y)
{
to[++tot] = y, nxt[tot] = head[x], head[x] = tot;
tr[++tot_r] = x, nr[tot_r] = hr[y], hr[y] = tot_r;
}
void tarjan(int x)
{
low[x] = dfn[x] = ++num;
st[++top] = x, in[x] = 1;
for (int i = head[x]; i; i = nxt[i])
{
int y = to[i];
if (!dfn[y])
tarjan(y), low[x] = min(low[x], low[y]);
else if (in[y])
low[x] = min(low[x], dfn[y]);
}
if (low[x] == dfn[x])
{
++scc;
int y;
do
{
y = st[top--], sc[y] = scc;
} while (x != y);
}
}
void dfs(int x)
{
vs[x] = 1;
for (int i = hr[x]; i; i = nr[i])
{
int y = tr[i];
if (!vs[y])
dfs(y);
}
}
int main()
{
scanf("%d%d", &N, &M);
for (int i = 1, x, y; i <= M; ++i)
scanf("%d%d", &x, &y), add(x, y);
tarjan(1);
int sum = 0, x = 0;
for (int i = 1; i <= N; ++i)
if (sc[i] == 1)
++sum, x = i;
if (x)
dfs(x);
for (int i = 1; i <= N; ++i)
if (!vs[i])
{
sum = 0;
break;
}
printf("%d\n", sum);
return 0;
}
若判断 S C C SCC SCC 缩点后的 D A G DAG DAG 是否仅存在一个出度为 1 1 1 的节点,需要构造出所有的 S C C SCC SCC。
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 10005, maxm = 50005;
int N, M, num, dfn[maxn], low[maxn];
int top, st[maxn], scc, sc[maxn], deg[maxn];
int tot, head[maxn], to[maxm], nxt[maxm];
bool in[maxn], vs[maxn];
inline void add(int x, int y)
{
to[++tot] = y, nxt[tot] = head[x], head[x] = tot;
}
void tarjan(int x)
{
low[x] = dfn[x] = ++num;
st[++top] = x, in[x] = 1;
for (int i = head[x]; i; i = nxt[i])
{
int y = to[i];
if (!dfn[y])
tarjan(y), low[x] = min(low[x], low[y]);
else if (in[y])
low[x] = min(low[x], dfn[y]);
}
if (low[x] == dfn[x])
{
++scc;
int y;
do
{
y = st[top--], sc[y] = scc;
} while (x != y);
}
}
int main()
{
scanf("%d%d", &N, &M);
for (int i = 1, x, y; i <= M; ++i)
scanf("%d%d", &x, &y), add(x, y);
for (int i = 1; i <= N; ++i)
if (!dfn[i])
tarjan(i);
int sum = 0;
for (int i = 1; i <= N; ++i)
if (sc[i] == 1)
++sum;
for (int i = 1; i <= N; ++i)
for (int j = head[i]; j; j = nxt[j])
{
int x = sc[i], y = sc[to[j]];
if (x != y)
++deg[x];
}
int cnt = 0;
for (int i = 1; i <= scc; ++i)
cnt += !deg[i];
printf("%d\n", cnt == 1 ? sum : 0);
return 0;
}