题意:给定一张N个点M条边的有向无环图,分别统计从每个点出发能够到达的点的数量。N,M<=30000。
思路:先拓扑排序,这样肯定拓扑序前面的肯定在拓扑序后面的点的前面。然后用状态压缩,用bitset转化成二进制,一顿从后往前按位或,有多少1就代表有多少个能达到的点的数量。
#include<cstdio> #include<cstring> #include<algorithm> #include<bitset> #include<cmath> #include<queue> #include<iostream> using namespace std; const int maxn = 30000+7; int head[maxn],ver[maxn]; int Next[maxn]; int tot,cnt; int deg[maxn],a[maxn]; int n,m; bitset<maxn> c[maxn]; void add(int x, int y){ ver[++tot] = y, Next[tot] = head[x]; head[x] = tot; deg[y]++; } void toposort(){ queue<int> q; for(int i = 1; i <= n; i++) if(deg[i] == 0) q.push(i); while(q.size()){ int x = q.front(); q.pop(); a[++cnt] = x; for(int i = head[x]; i; i = Next[i]) { int y = ver[i]; deg[y]--; if(deg[y] == 0) q.push(y); } } } void solve(){ int x, y; for(int i = cnt; i >= 1; i--) { x = a[i]; c[x][x] = 1; for(int j = head[x]; j; j = Next[j]) { int y = ver[j]; c[x] |= c[y]; } } } int main(){ int x, y; scanf("%d %d", &n, &m); while(m--){ scanf("%d %d", &x, &y); add(x, y); } toposort(); solve(); for(int i = 1; i <= n; i++) printf("%d\n",c[i].count()); return 0; }