题意:给定一张N个点M条边的有向无环图,分别统计从每个点出发能够到达的点的数量
思路:该题的暴力做法就是从每个点开始dfs,就能得到每个点最多可到达的点的数量,但很明显会超时。先对图进行拓扑排序,这样可以由拓扑序由后向前递推。一种很妙的做法是使用bitset进行状态压缩,用一个3000位的二进制数来表示一个点的状态,对于第i个点,考虑与其直接相连的边,如果j与其相连,则该二进制的第j位为1。可以看到,当我们按照拓扑序逆着遍历时,每个点所指向的其他点必定都被考虑过了,故此点的状态等于之前其他点的状态的bitwise or和。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<bitset>
using namespace std;
const int MAXN = 3e4+5;
int n, m;
int in_degree[MAXN];
int head[MAXN], tot;
struct Edge{
int to, next;
}edge[MAXN];
void addEdge(int u, int v){
edge[tot].to = v;
edge[tot].next = head[u];
head[u] = tot++;
}
int a[MAXN], cnt;
void topoSort(){
queue<int> q;
for(int i = 1; i <= n; ++i){
if(in_degree[i] == 0) q.push(i);
}
while(!q.empty()){
int now = q.front();
q.pop();
a[++cnt] = now;
for(int i = head[now]; i != -1; i = edge[i].next){
int v = edge[i].to;
in_degree[v]--;
if(in_degree[v] == 0){
q.push(v);
}
}
}
}
bitset<MAXN> f[MAXN];
void solve(){
for(int i = cnt; i > 0; --i){
int x = a[i];
f[x][x] = 1;
for(int j = head[x]; j != -1; j = edge[j].next){
int y = edge[j].to;
f[x] = f[x] | f[y];
}
}
}
int main()
{
memset(head, -1, sizeof(head));
cin >> n >> m;
int x, y;
for(int i = 1; i <= m; ++i)
{
cin >> x >> y;
addEdge(x, y);
in_degree[y]++;
}
topoSort();
solve();
for(int i = 1; i <= n; ++i)
cout << f[i].count() << endl;
return 0;
}