Cactus HDU

原题链接

#include <iostream>
#include <vector>
#include <cstring>
#include <queue>


using namespace std;
const int N = 20009;
const int M = 150000;
int h[M], ne[M], to[M], idx;
int dfn[N], low[N], times;
int instk[N], stk[N], top;
int sz[N], id[N], scc_cnt;
void add(int u, int v) {ne[idx] = h[u], to[idx] = v, h[u] = idx++;}
int f;
void tarjan(int u) {
    dfn[u] = low[u] =  ++ times;
    stk[++top] = u;
    instk[u] = 1;
    int cnt = 0;
    for (int i = h[u]; i != -1; i = ne[i]) {
        int v = to[i];

        if (!dfn[v]) {
            tarjan(v);
            low[u] = min(low[u], low[v]);
        } else if (instk[v]) {
            low[u] = min(low[u], dfn[v]);
        }
        if (!instk[u])f = 1;//没有横插边,设想一下,一条边伸到了一个不在当前强连通分量的地方。
        if (low[v] > dfn[u]) {
            f = 1;//如果自己儿子的边回不来,那么必然就是一个桥,直接通向别处
        }
        if (dfn[v] < dfn[u]) cnt++;//首先是儿子的向上碰到自己祖先的数量
    }
    if (cnt > 1) {
        f = 1;
    }
    if (low[u] == dfn[u]) {
        scc_cnt++;
        int v = stk[top];
        do{
            v = stk[top];
            top--;
            instk[v] = 0;
            sz[scc_cnt] ++;
            id[v] = scc_cnt;
        } while (v != u);
    }
}
void solve() {
    times = top = idx = scc_cnt = f = 0;
    memset(h, -1, sizeof h);
    memset(dfn, 0, sizeof dfn);
    memset(sz, 0, sizeof sz);
    int n;cin >> n;
    int u, v;
    while (cin >> u >> v) {
        if( u == 0 && v == 0)break;
        add(u, v);
    }
    for (int i = 0; i < n; i ++) {
        if (!dfn[i])tarjan(i);
    }
    if (scc_cnt == 1 && !f) cout << "YES
";
    else cout << "NO
";
}
int main() {
    int t = 1;cin >> t;
    while (t--)solve();
    return 0;
}
原文地址:https://www.cnblogs.com/Xiao-yan/p/14629510.html