强连通分量的题,tarjan算法
然后缩点,记a为入度为0的点的个数,b为出度为0的点的个数,ans = max(a, b);
特殊情况缩点后只有一个点 ans = 0;
#include<cstdio>
#include<cstring>
#include<vector>
#include<stack>
#include<algorithm>
using namespace std;
const int MAXN = 20007;
int pt[MAXN], low[MAXN];
int sccn, sccno[MAXN];
int in[MAXN], out[MAXN];
int dt;
vector<int> G[MAXN], scc[MAXN];
stack<int> stk;
int dfs(int u) {
pt[u] = low[u] = ++dt;
stk.push(u);
int i, v, sz = G[u].size();
for(i = 0; i < sz; i++) {
v = G[u][i];
if( !pt[v]) low[u] = min(low[u], dfs(v));
else if( !sccno[v]) low[u] = min(low[u], pt[v]);
}
if(low[u] == pt[u]) {
sccn ++;
while( !stk.empty()) {
v = stk.top(); stk.pop();
sccno[v] = sccn;
if(v == u) break;
}
}
return low[u];
}
void getscc(int n) {
while( !stk.empty()) stk.pop();
sccn = dt = 0;
memset(pt, 0 ,sizeof(pt));
memset(sccno, 0, sizeof(sccno));
for(int i = 1; i <= n; i++)
if( !pt[i]) dfs(i);
}
int main() {
int n, m, T;
scanf("%d", &T);
while(T--) {
scanf("%d%d", &n ,&m);
int i, j, u, v;
for(i = 1; i <= n; i++)G[i].clear();
for(i = 1; i <= m; i++) {
scanf("%d%d", &u, &v);
G[u].push_back(v);
}
getscc(n);
memset(in, 0, sizeof(in));
memset(out, 0, sizeof(out));
for(i = 1; i <= n; i ++) {
int sz = G[i].size();
for(j = 0; j < sz; j++) {
if( sccno[i] == sccno[G[i][j]]) continue;
out[sccno[i]] ++;
in[sccno[G[i][j]]] ++;
}
}
int a = 0, b = 0;
for(i = 1; i <= sccn; i++) {
if( !out[i]) a++;
if( !in[i]) b++;
}
int ans = max(a, b);
if(sccn == 1) ans = 0;
printf("%d\n", ans);
}
return 0;
}