bitset用法和ch2101可达性统计

我又回来啦

第一次尝试使用markdown文本,可能编辑不好,见谅咕咕咕

题目

(这个网站里有全部蓝书的题目,qq登录即可,good)

咳咳下面步入正题,关于这种题目,看到的第一眼应该能想到相当于动规的递推,但是要求边界如果直接dfs,30000的数据不知道你家的栈能不能的住
所以这个题目提供了一个很好的思路,就是先求出拓扑序然后反过来一个一个求,这样可以保证求当前节点数据时(小于等于30000不用longlong)所用到的节点都以经算好了,就这么简单

就这么简单??

你好好考虑过动归方程了吗?
f(x)={x}并(所有f(y)的并,存在有向边(x,y))
为甚不是加??
因为有可能会有重复。比如3->4,2->4那直接加起来,4就会算两次
怎么破??

主角闪亮登场!!

状压

用N位二进制数,反之一个点到其他点只有能与不能
1就是能呗,2就是不能呗
实现:

  1. 数组实现(不够装逼)
  2. bitset!

一直不知道bitset怎么用
今天先码几个呗( 嘤嘤嘤

1:定义

bitset<大小>名称
bitset<大小>名称[数组大小]

2:运算

假设有bit[30001]
可以直接赋值bit[1][1]=1;
或者bit[1]="10011"; 注意是字符串,前面补0
就是第一个1位为1

可以直接bit[1]|bit[2] (全部按位或)

2019.12.15 20.14--------------------

3:复杂度

bitset 就是通过固定的优化,使得一个字节的八个比特能分别储存 8 位的 0/1 。
对于一个 4 字节的 int 变量,bitset 占用空间只是其1/32,计算一些信息时,所需时间也是其1/32。 --来源
赚啊 滑稽

4:成员函数

.count()返回1的个数
其实还有很多,但最多用的(状压中)也就是这个了吧

——————————
下面也就是状压的常规操作了,也没啥好说的了。下面到了最快乐的

code time
//CH2101
#include<iostream>
#include<bitset>
#include<queue>
using namespace std;
#define N 30005

bitset<N> bit[N];
queue<int>q;
struct xx{
    int to,nxt;
}e[N];int hd[N],num;

inline void add(int fm,int to){
    e[++num].to=to;e[num].nxt=hd[fm];
    hd[fm]=num;
}
int topo[N],d[N],cnt;
int n,m;

void tp(){
    for(int i=1;i<=n;i++)
    if(!d[i])q.push(i),topo[++cnt]=i;
    while(!q.empty()){
        int x=q.front();
        q.pop();
        for(int t=hd[x];t;t=e[t].nxt){
            int y=e[t].to;
            d[y]--;
            if(!d[y])q.push(y),topo[++cnt]=y;
        }
    }
}
int main(){
    cin>>n>>m;
    for(int x,y,i=1;i<=m;i++){
        cin>>x>>y;
        add(x,y);
        d[y]++;
    }
    tp();
    for(int i=cnt;i;i--){  //由于这是按tp序来的,所有子节点都以经ok了
        int x=topo[i];
        bit[x][x]=1;
        for(int t=hd[x];t;t=e[t].nxt){
            bit[x]|=bit[e[t].to];  //可以直接按位或
        }
    }
    for(int i=1;i<=n;i++) cout<<bit[i].count()<<endl;
    // char c=getchar();
    return 0;
}
posted @ 2019-12-15 20:15  千陌  阅读(271)  评论(0编辑  收藏  举报