AcWing 164. 可达性统计


题目传送门

一、前导知识

二、本题分析



三、实现代码

#include 

using namespace std;
const int N = 30010, M = 30010;
int n, m;
int d[N];
bitset f[N];   //这相当于一个二维数组,表示点i(一维),可以到达其它哪些点,用类似于二进制的方式描述
vector path; //拓扑序路径
//邻接表
int e[M], h[N], idx, ne[M];
void add(int a, int b) {
    e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}

void topsort() {
    queue q;
    for (int i = 1; i <= n; i++)
        if (!d[i])
            q.push(i);

    while (q.size()) {
        int t = q.front();
        q.pop();
        path.push_back(t);
        for (int i = h[t]; ~i; i = ne[i]) {
            int j = e[i];
            if (--d[j] == 0)
                q.push(j);
        }
    }
}

int main() {
    memset(h, -1, sizeof h);
    cin >> n >> m;
    int a, b;
    for (int i = 0; i < m; i++) {
        cin >> a >> b;
        add(a, b);
        d[b]++;
    }
    //求拓扑序
    topsort();

    //倒序输出拓扑序
    for (int i = n - 1; i >= 0; i--) {
        int j = path[i];
        f[j][j] = 1;                      // 自己到自己是一种方案 base case
        for (int k = h[j]; ~k; k = ne[k]) // 枚举节点j的每条出边
            f[j] |= f[e[k]];              //通过二进制或运算,可以获取到j点可以到达哪些点e[k]
    }
    //输出个数
    for (int i = 1; i <= n; i++) printf("%d\n", f[i].count());
    return 0;
}