164. 可达性统计

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

输入格式

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

输出格式

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

数据范围

1N,M300001≤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

题意分析:
题目已经说明白,给我们的是DAG(有向无环图)。既然是DAG,可以很容易的联想到拓扑排序。题目让我们统计每个点出发能到达的点的数量,我们可以先模拟一下样例,如下图(只例举出1,2,3三个点)。

题解:
综上所述,设从点 x 出发能够到达的点构成的集合是 f(x),从点 x 出发能够到达的点,是从 x 的各个后继节点 y 出发能够到达的点的并集,再加上点 x 自身 。
f(2) = f(3) ∪ f(5) ∪ f(10) = …
先按照拓扑排序算法求出拓扑序,然后按照拓扑序的倒叙进行计算------因为在拓扑序中,任意一条边 (x , y),x 都排在 y 之前。
关于状态压缩 bitset容器:
转载:https://oi-wiki.org/ds/stl/bitset/


介绍¶
std :: bitset 是标准库中的一个固定大小序列,其储存的数据只包含 0/1
众所周知,由于内存地址是按字节即 byte 寻址,而非比特 bit ,
我们一个 bool 类型的变量,虽然只能表示 0/1 , 但是也占了 1byte 的内存
bitset 就是通过固定的优化,使得一个字节的八个比特能分别储存 8 位的 0/1
对于一个 4 字节的 int 变量,在只存 0/1 的意义下, bitset 占用空间只是其
在某些情况下通过 bitset 可以使你的复杂度除以 32
当然, vector 的一个特化 vector<bool> 的储存方式同 bitset 一样,区别在于其支持动态开空间,
bitset 则和我们一般的静态数组一样,是在编译时就开好了的。
那么为什么要用 bitset 而非 vector<bool> ?
通过以下的介绍,你可以更加详细的看到 bitset 具备的方便操作
#include <bitset> // 包含 bitset 的头文件


运算符¶


operator[] : 访问其特定的一位


operator ==/!= : 比较两个 bitset 内容是否完全一样


operator &=/|=/^=/~ : 进行按位与/或/异或/取反操作


operator <</>>/<<=/>>= : 进行二进制左移/右移


operator <</>> : 流运算符,这意味着你可以通过 cin/cout 进行输入输出


vector<bool> 只具有前两项
成员函数¶

test() : 它和 vector 中的 at() 的作用是一样的,和 [] 运算符的区别就是越界检查
count() : 返回 true 的数量
set() : 将整个 bitset 设置成 true , 你也可以传入参数使其设置成你的参数
reset() : 将整个 bitset 设置成 false
flip() : 翻转该位 (0 变 1,1 变 0), 相当于逻辑非/异或 1
to_string() : 返回转换成的字符串表达
to_ulong() : 返回转换成的 unsigned long 表达 ( long 在 NT 及 32 位 POSIX 系统下与 int 一样,在 64 位 POSIX 下与 long long 一样)
to_ullong() C++11, 返回转换成的 unsigned long long 表达

这些 vector<bool> 基本都没有
作用¶
一般来讲,我们可以用 bitset 优化一些可行性 DP, 或者线筛素数 ( notprime 这种 bool 数组可以用 bitset 开到 之类的)
它最主要的作用还是压掉了内存带来的时间优化, 的常数优化已经可以是复杂度级别的优化了,比如一个 的 算法, 显然很卡,在常数大一点的情况下必然卡不过去,O(松)不能算!, 这时候如果我们某一维除以 32, 则可以比较保险的过了这道题
其实 bitset 不光是一个容器,更是一种思想,我们可以通过手写的方式,来把 long long 什么的压成每 bit 表示一个信息,用 STL 的原因更多是因为它的运算符方便

 1 #include <iostream>
 2 #include <cstring>
 3 #include <bitset>
 4 #include <algorithm>
 5 #include <queue>
 6 using namespace std;
 7 int n,m;
 8 const int maxn=3e4+5;
 9 bitset<maxn> f[maxn];
10 int h[maxn],e[maxn],ne[maxn],idx;
11 int seq[maxn],in[maxn];
12 
13 void add(int a,int b){
14     e[idx]=b,ne[idx]=h[a],h[a]=idx++;
15 }
16 
17 void topsort(){
18     queue<int> que;
19     for(int i=1;i<=n;i++){
20         if(in[i]==0) que.push(i);
21     }
22     int jishu=0;
23     while(!que.empty()){
24         int top=que.front();
25         que.pop();
26         seq[jishu++]=top;
27         for(int j=h[top];~j;j=ne[j]){
28             int ee=e[j];   //与其相连的那条边
29             if(--in[ee]==0) que.push(ee);
30         }
31     }
32 }
33 
34 int main(){
35     cin>>n>>m;
36     memset(h,-1,sizeof(h));
37     for(int i=1;i<=m;i++){
38         int d1,d2;
39         cin>>d1>>d2;
40         add(d1,d2);
41         in[d2]++;
42     }
43     topsort();
44     for(int i=n-1;i>=0;i--){
45         int j=seq[i];
46         f[j][j]=1;
47         for(int k=h[j];~k;k=ne[k]){
48             f[j]|=f[e[k]];
49         }
50     }
51     for(int i=1;i<=n;i++){
52         cout << f[i].count() << endl;
53     }
54     return 0;
55 }
邻接表建图
  1 #include <iostream>
  2 #include <cstring>
  3 #include <bitset>
  4 #include <algorithm>
  5 #include <queue>
  6 using namespace std;
  7 int n,m;
  8 const int maxn=3e4+5;
  9 bitset<maxn> f[maxn];
 10 int h[maxn],e[maxn],ne[maxn],idx;
 11 int seq[maxn],in[maxn];
 12 
 13 void add(int a,int b){
 14     e[idx]=b,ne[idx]=h[a],h[a]=idx++;
 15 }
 16 
 17 void topsort(){
 18     queue<int> que;
 19     for(int i=1;i<=n;i++){
 20         if(in[i]==0) que.push(i);
 21     }
 22     int jishu=0;
 23     while(!que.empty()){
 24         int top=que.front();
 25         que.pop();
 26         seq[jishu++]=top;
 27         for(int j=h[top];~j;j=ne[j]){
 28             int ee=e[j];   //与其相连的那条边
 29             if(--in[ee]==0) que.push(ee);
 30         }
 31     }
 32 }
 33 
 34 int main(){
 35     cin>>n>>m;
 36     memset(h,-1,sizeof(h));
 37     for(int i=1;i<=m;i++){
 38         int d1,d2;
 39         cin>>d1>>d2;
 40         add(d1,d2);
 41         in[d2]++;
 42     }
 43     topsort();
 44     for(int i=n-1;i>=0;i--){
 45         int j=seq[i];
 46         f[j][j]=1;
 47         for(int k=h[j];~k;k=ne[k]){
 48             f[j]|=f[e[k]];
 49         }
 50     }
 51     for(int i=1;i<=n;i++){
 52         cout << f[i].count() << endl;
 53     }
 54     return 0;
 55 }
 56 
 57 
 58 
 59 #include <iostream>
 60 #include <cstring>
 61 #include <bitset>
 62 #include <algorithm>
 63 #include <queue>
 64 using namespace std;
 65 int n,m;
 66 const int maxn=3e4+5;
 67 bitset<maxn> f[maxn];
 68 vector<int> G[maxn];
 69 int seq[maxn],in[maxn];
 70 
 71 void topsort(){
 72     queue<int> que;
 73     for(int i=1;i<=n;i++){
 74         if(in[i]==0) que.push(i);
 75     }
 76     int jishu=0;
 77     while(!que.empty()){
 78         int top=que.front();
 79         que.pop();
 80         seq[jishu++]=top;
 81         for(auto X:G[top]){
 82             if(--in[X]==0) que.push(X);
 83         }
 84     }
 85 }
 86 
 87 int main(){
 88     cin>>n>>m;
 89     for(int i=1;i<=m;i++){
 90         int d1,d2;
 91         cin>>d1>>d2;
 92         G[d1].push_back(d2);
 93         in[d2]++;
 94     }
 95     topsort();
 96     for(int i=n-1;i>=0;i--){
 97         int j=seq[i];
 98         f[j][j]=1;
 99         for(auto X:G[j]){
100             f[j]|=f[X];
101         }
102     }
103     for(int i=1;i<=n;i++){
104         cout << f[i].count() << endl;
105     }
106     return 0;
107 
108 
109 }
vector建图


原文地址:https://www.cnblogs.com/qq-1585047819/p/11551896.html