可达性统计

给定一张N个点M条边的有向无环图,分别统计从每个点出发能够到达的点的数量。

输入格式

第一行两个整数N,M,接下来M行每行两个整数x,y,表示从x到y的一条有向边。

输出格式

输出共N行,表示每个点能够到达的点的数量。

数据范围

1≤N,M≤30000

输入样例:

1
2
3
4
5
6
7
8
9
10
11
10 10
3 8
2 3
2 5
5 9
5 9
2 3
3 9
4 8
2 10
4 9

输出样例:

1
2
3
4
5
6
7
8
9
10
1
6
3
3
2
1
1
1
1
1

解题思路

本题需要进行拓扑排序,f[i]表示第i个点能到的所有点, 最后倒序先统计入度大的点能到达点的数目

代码实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
#include <bitset>
using namespace std;
const int N = 30005;
int to[N], h[N], idx;
int n, m, d[N], se[N], ne[N], k;
bitset<N> f[N]; //bitset32位优化
void add(int u, int v)
{
to[idx] = v, ne[idx] = h[u], h[u] = idx ++;
}
void topsort()
{
queue<int> q;
for(int i = 1; i <= n; i ++ )
if(d[i] == 0) //初始入度为0入队
q.push(i);
k = 0;
while(q.size())
{
int u = q.front();
q.pop();
se[++ k] = u;
for(int i = h[u]; ~i; i = ne[i])
{
int j = to[i];
if(-- d[j] == 0) //相邻点入度为0入队
q.push(j);
}
}
}

int main()
{
memset(h, -1, sizeof(h));
int u, v;
cin >> n >> m;
for(int i = 0; i < m; i ++ )
{
cin >> u >> v;
add(u, v);
d[v] ++;
}

topsort();

for(int i = k; i >= 1; i -- )
{
int t = se[i];
f[t][t] = 1; //自身到自身为1
for(int j = h[t]; ~j; j = ne[j])
f[t] |= f[to[j]];
}

for(int i = 1; i <= n; i ++ )
cout << f[i].count() << endl; //f[i].count()直接统计1的个数
return 0;
}
0%