Popular Cows

OJ: POJ

题目 ID: 2186

标签: scc

日期: 2025-12-29 14:07

题目解析

与 [[problem: luogu,P2341]] 是同一个题目,注意代码修改成 c++98 的形式

代码

cpp
/**
 * Author by Rainboy blog: https://rainboylv.com github : https://github.com/rainboylvx
 * rbook: -> https://rbook.roj.ac.cn  https://rbook2.roj.ac.cn
 * date: 2025-12-29 10:52:38
 */
#include <iostream>
#include <cstring>   // 必须包含:用于 memset
#include <stack>     // 必须包含:用于 stack
#include <algorithm> // 必须包含:用于 std::min
#include <vector>

using namespace std;
typedef  long long ll;
typedef  unsigned long long ull;

const int maxn = 2e6+5;
const int maxe = 4e6+5;
const int mod = 1e9+7;

int n, m;

struct linkList {
    typedef struct {int u,v,w,next;} edge;
    edge e[maxe];
    int h[maxn];
    int edge_cnt; // C++98 错误修复:不能在这里写 = 0

    linkList(){
        edge_cnt = 0; // 必须在构造函数中初始化
        reset();
    }

    void reset() {
        edge_cnt = 0;
        memset(h, -1, sizeof(h));
    }

    void add(int u,int v,int w=0){
        // C++98 下,手动赋值最安全
        e[edge_cnt].u = u;
        e[edge_cnt].v = v;
        e[edge_cnt].w = w;
        e[edge_cnt].next = h[u];
        h[u] = edge_cnt++;
    }

    int operator()(int u){ return h[u]; }
    edge& operator[](int i){ return e[i]; }
} e;

struct TarjanScc {
    int n, timer;
    std::stack<int> st; // 修复:需要 #include <stack>
    bool in_stack[maxn];
    int dfn[maxn], low[maxn], scc_id[maxn];
    int scc_cnt; 
    int sz[maxn]; 

    void set(int _n) {
        n = _n;
        timer = scc_cnt = 0;
        memset(dfn, 0, sizeof(dfn));     // 修复:需要 #include <cstring>
        memset(in_stack, 0, sizeof(in_stack));
        memset(sz, 0, sizeof(sz));
        // 清空栈,防止多组数据残留
        while (!st.empty()) st.pop();
    }

    void dfs(int u) {
        dfn[u] = low[u] = ++timer;
        st.push(u);
        in_stack[u] = true;

        for (int i = e(u); ~i ; i = e[i].next) {
            int v = e[i].v;
            if (!dfn[v]) {
                dfs(v);
                low[u] = std::min(low[u], low[v]); // 需要 <algorithm>
            } else if (in_stack[v]) {
                low[u] = std::min(low[u], dfn[v]);
            }
        }

        if (low[u] == dfn[u]) {
            scc_cnt++;
            while (1) {
                int v = st.top(); st.pop();
                in_stack[v] = 0;
                scc_id[v] = scc_cnt;
                sz[scc_cnt]++; 
                if (v == u) break;
            }
        }
    }

    void solve() {
        for (int i = 1; i <= n; i++) {
            if (!dfn[i]) dfs(i);
        }
    }
} tscc;

int out_degree[maxn]; 

int main () {
    // 建议在 C++98 中显式包含 stdio 相关的同步关闭,虽然这里用了 iostream
    ios::sync_with_stdio(false); 
    cin.tie(NULL); // C++98 用 NULL 或 0,不要用 nullptr
    
    if(!(cin >> n >> m)) return 0;
    
    for(int i = 0; i < m; i++) {
        int u, v;
        cin >> u >> v;
        e.add(u, v);
    }

    tscc.set(n);
    tscc.solve();

    // 遍历所有原图的边,统计 SCC 的出度
    for(int i = 0; i < e.edge_cnt; i++) {
        int u = e.e[i].u;
        int v = e.e[i].v;
        // 如果边连接了两个不同的 SCC
        if(tscc.scc_id[u] != tscc.scc_id[v]) {
            out_degree[tscc.scc_id[u]]++;
        }
    }

    int zero_out_cnt = 0; // 出度为 0 的 SCC 数量
    int star_scc_idx = 0; // 记录出度为 0 的 SCC 编号

    for(int i = 1; i <= tscc.scc_cnt; i++) {
        if(out_degree[i] == 0) {
            zero_out_cnt++;
            star_scc_idx = i;
        }
    }

    if(zero_out_cnt == 1) {
        cout << tscc.sz[star_scc_idx] << endl;
    } else {
        cout << 0 << endl;
    }

    return 0;
}