Tarjan模板题。建议采用二维vector存储。
学习Tarjan时要注意两个数组:
int DFN[M]; //深度优先搜索访问次序
int Low[M]; //能追溯到的最早的次序
这是学习的网址:http://www.nocow.cn/index.php/Tarjan算法
P.s. Tarjan真心是递归之精髓的体现啊!
下面是标准的Tarjan的模板。
这道题算法其实很清楚,把图的边反向存储,再把图的强连通分量求出来,然后找出入度为零的分量,如果入度为0的强连通分量个数大于1,那么最终解一定是0,否则最终解就是那个入度为零的强连通分量的点的个数。
#include <iostream>
#include <string.h>
#include <vector>
#define MAX_N 10010
#define MAX_M 50010
using namespace std;
vector <int> vec[MAX_N];
int dfn[MAX_N], low[MAX_N], stap[MAX_N], belong[MAX_N];
int n, m, bcnt, dindex = 0, stop = 0;
int rd[MAX_N], rd0cnt;
bool instack[MAX_N];
int x[MAX_M], y[MAX_M];
void tarjan(int v) {
int u, l = vec[v].size();
dfn[v] = low[v] = ++dindex;
instack[v] = true;
stap[++stop] = v;
for (int i = 0; i < l; i++) {
u = vec[v][i];
if (!dfn[u]) {
tarjan(u);
if (low[u] < low[v])
low[v] = low[u];
}
else if (instack[u] && dfn[u] < low[v])
low[v] = dfn[u];
}
if (dfn[v] == low[v]) {
bcnt++;
do {
u = stap[stop--];
instack[u] = false;
belong[u] = bcnt;
}
while (u != v);
}
}
int main() {
while (cin >> n >> m) {
for (int i = 1; i <= m; i++) {
cin >> x[i] >> y[i];
vec[y[i]].push_back(x[i]);
}
stop = bcnt = dindex = 0;
memset(dfn, 0, sizeof(dfn));
for (int i = 1; i <= n; i++)
if (!dfn[i]) tarjan(i);
memset(rd, 0, sizeof(rd));
for (int i = 1; i <= m; i++)
if (belong[x[i]] != belong[y[i]])
rd[belong[x[i]]]++;
int cnt = 0;
for (int i = 1; i <= bcnt; i++)
if (rd[i] == 0) cnt++;
if (cnt > 1) cout << 0 << endl;
else {
cnt = 0;
for (int i = 1; i <= n; i++)
if (rd[belong[i]] == 0) cnt++;
cout << cnt << endl;
}
}
}