CH2101:【可达性统计】(拓扑排序+状态压缩)

设从点 x 出发能够到达的点构成的集合是 f(x),从点 x 出发能够到达的点,是从 x 的各个后继节点 y 出发能够到达的点的并集,再加上点 x 自身 。

比如从2出发可以到达点5 8 9,则f(2)=f(5)Uf(8)Uf(9)

先按照拓扑排序算法求出拓扑序,然后按照拓扑序的倒序进行计算------因为在拓扑序中,任意一条边 (x , y),x 都排在 y 之前。

我们可以用一个N位2进制数来表示每个f(x),二进制数的第i位为1表示x可以到达点i,二进制中1的个数就是这个点可以到达的点的数目,这样一来,对若干个集合求并集,就是对若干个N位二进制数做按位或

用bitset存储f(x)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 3e4 + 10;
vector<int>edge[maxn], ans;
queue<int> que;
bitset<maxn> b[maxn];
int in[maxn], n, m,x,y;
void topo_sort()
{
    for (int i = 1; i <= n;i++)
        if (!in[i]) que.push(i);
    while (!que.empty())
    {
        int v = que.front();
        que.pop();
        ans.push_back(v);
        for (int i = 0; i < edge[v].size(); i++)
        {
            if (--in[edge[v][i]] == 0) 
                que.push(edge[v][i]);
        }
    }
}
void solve()
{
    topo_sort();
    for (int i = ans.size() - 1; i>=0; i--)
    {
        int v = ans[i];
        //b[v].reset();
        b[v][v] = 1;
        for (int j = 0; j < edge[v].size(); j++)
        {
            b[v] |= b[edge[v][j]];
        }
    }
    for (int i = 1; i <= n; i++)
        cout << b[i].count() << endl;
}
int main()
{
    cin >> n >> m;
    for (int i = 1; i <= m; i++)
    {
        cin >> x >> y;
        edge[x].push_back(y);
        in[y]++;
    }
    solve();
    return 0;
}
原文地址:https://www.cnblogs.com/xiaoguapi/p/10383319.html