可達性統計
阿新 • • 發佈:2020-07-27
給定一張N個點M條邊的有向無環圖,分別統計從每個點出發能夠到達的點的數量。
輸入格式
第一行兩個整數N,M,接下來M行每行兩個整數x,y,表示從x到y的一條有向邊。
輸出格式
輸出共N行,表示每個點能夠到達的點的數量。
資料範圍
1≤N,M≤30000<?XML:NAMESPACE PREFIX = "[default] http://www.w3.org/1998/Math/MathML" NS = "http://www.w3.org/1998/Math/MathML" />1≤N,M≤30000
輸入樣例:
10 10
3 8
2 3
2 5
5 9
5 9
2 3
3 9
4 8
2 10
4 9
輸出樣例:
1 6 3 3 2 1 1 1 1 1
首先,要求的是每個點出發能到達的點數包括它本身。注意是有向無環圖。
思路:
1. 由推導可知(一看就知道嘿嘿),假設當前點是 x, 則通過x能到達的點,是由x
所指向的點的指向的點的…..,的集合。
2. 設f(x)為x點能到達的點數,
f(x) = {x} U {f(son1), f(son2), …};//這裡的son代表x指向的點,f(son)就是兒子能到
達的點數。
3.通過2的公式可以得知,計算應該從尾巴節點開始算,然後一步步累加, 所以我們可以先求出無向圖的
拓撲排序,然後反向的計算,因為拓撲排序反過來就是從尾巴開始的。
4。看資料是30000,所以直接開二維陣列會爆,這個時候就要用到二進位制狀態壓縮,STL庫中有bitset
直接用就ok
程式碼:
#include <iostream> #include <algorithm> #include <cstring> #include <bitset> #include <queue> using namespace std; const int N = 30010; int n, m; int h[N], e[N], ne[N], idx; int d[N], seq[N];//seq存拓撲排序 bitset<N> f[N]; void add(int a, int b) {//鄰接表存圖 e[idx] = b, ne[idx] = h[a], h[a] = idx++; } voidtopsort() { queue<int> q; for(int i = 1; i <= n; ++ i){ if(!d[i]) q.push(i);//入度為零的點加入佇列 } int k = 0; while(!q.empty()) { int t = q.front(); q.pop(); seq[k++] = t; for(int i = h[t]; ~i; i = ne[i]) { int j = e[i]; if(-- d[j] == 0)//入度為零的點加入佇列 q.push(j); } } } int main() { cin >> n >> m; memset(h, -1, sizeof h); for(int i = 0; i < m; ++ i) { int a, b; cin >> a >> b; add(a,b); d[b] ++;//計算入度 } topsort(); for(int i = n - 1; ~i; -- i){ int j = seq[i];//j點指向的下一個點 f[j][j] = 1;//到它自己也算一個點 for(int p = h[j]; ~p; p = ne[p]) f[j] |= f[e[p]];//將對應的二進位制位變成1 } for(int i = 1; i <= n; ++ i) cout << f[i].count() << endl;//統計每個點的二進位制位1的個數就是答案 return 0; }