可达性

思路

利用有向图的强连通分量中的tarjan算法进行缩点, 输出缩点后的图中入度为0的结点编号, 缩点后的图中结点编号为该点对应强连通分量中点编号的最小值

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
int dx[] = {-1, 1, 0, 0}, dy[] = {0, 0, -1, 1};
const double eps = 1e-6;
const int N = 1e5 + 10;
int n, m;
int h[N], e[N], ne[N], idx;
int timestamp, stk[N], top;
int low[N], dfn[N];
vector<int> scc[N];
int scc_cnt, id[N];
bool in_stk[N];
int min_of_scc[N], din[N]; // min_of_scc[i]表示第i个强连通分量中最小的点编号

void add(int a, int b)
{
    e[idx] = b;
    ne[idx] = h[a];
    // w[idx] = c;
    h[a] = idx++;
}

void tarjan(int u)
{
    low[u] = dfn[u] = ++timestamp;
    stk[++top] = u;
    in_stk[u] = true;

    for (int i = h[u]; i != -1; i = ne[i])
    {
        int j = e[i];
        if (!dfn[j])
        {
            tarjan(j);
            low[u] = min(low[u], low[j]);
        }
        else if (in_stk[j])
        {
            low[u] = min(low[u], dfn[j]);
        }
    }

    if (dfn[u] == low[u])
    {
        int y;
        scc_cnt++;
        do
        {
            y = stk[top--];
            in_stk[y] = false;
            id[y] = scc_cnt;
            scc[scc_cnt].push_back(y);
            min_of_scc[scc_cnt] = min(min_of_scc[scc_cnt], y);
        } while (y != u);
    }
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    memset(h, -1, sizeof h);
    memset(min_of_scc, 0x3f, sizeof min_of_scc);

    cin >> n >> m;
    while (m--)
    {
        int u, v;
        cin >> u >> v;
        add(u, v);
    }

    for (int i = 1; i <= n; i++)
    {
        if (!dfn[i])
            tarjan(i);
    }

    for (int u = 1; u <= n; u++)
    {
        for (int i = h[u]; i != -1; i = ne[i])
        {
            int j = e[i];
            in***], b = id[j];
            if (a != b)
                din[min_of_scc[b]]++;
        }
    }

    vector<int> ans;
    for (int i = 1; i <= scc_cnt; i++)
    {
        if (!din[min_of_scc[i]])
            ans.push_back(min_of_scc[i]);
    }
    sort(ans.begin(), ans.end());
    cout << ans.size() << '\n';
    for (int i : ans)
        cout << i << ' ';
    return 0;
}