bitset 优化01背包 处理集合

好博客: https://www.cnblogs.com/cjjsb/p/9751384.html

例题1:Newcoder 132C 简单瞎搞题

题目链接:https://www.nowcoder.com/acm/contest/132/C

题意:

 

分析:核心就在于看作01背包的形式,枚举种类n,每个范围(L-R+1),以及所有的可能值 1~1e6,

然后直接做的话又会超时,所以要用到 bitset 的位运算,将b[0][0]设置为1,每次向左移动 j*j 位,最后就可以得到经过所有组合后的可能取值。

#include <cstdio>
#include <bitset> 
using namespace std;
bitset<1000005>b[105];
int n,l[105],r[105];
int main()
{
    scanf("%d",&n);
    int Min=0;
    for(int i=1;i<=n;i++) {scanf("%d%d",&l[i],&r[i]); Min+=l[i]*l[i];}
    b[0].set(0);
    //上面那句就等同于 -> b[0][0]=1;
    for(int i=1;i<=n;i++)
        for(int j=l[i];j<=r[i];j++)
            b[i]|=(b[i-1]<<(j*j));
    
    // int ans=0;
    // for(int i=Min; i<=1000005; i++){
    //     if(b[n][i]) ans++;
    // }
    // printf("%d\n", ans);
    printf("%d\n",b[n].count());
    return 0;
}

 例题2:POJ-2443

题目链接:https://vjudge.net/problem/POJ-2443

题意:分析某两个元素是否存在于共同的集合。

#include <cstdio>
#include <cstring>
#include <bitset>
using namespace std;

const int maxn = 1e5+3;
bitset<1000> a[10000],t; 
int main(){
    int q,n,m,k;
    scanf("%d",&n);
    for(int i=0; i<n; i++){
        scanf("%d",&m);
        for(int j=0; j<m; j++){
            scanf("%d",&k);
            a[k][i] = 1;
        }
    }
    scanf("%d",&q);
    int x,y;
    for(int i=0; i<q; i++){
        scanf("%d%d",&x,&y);
        t = a[x]&a[y];
        if( t.count() ){
            printf("Yes\n");
        }
        else{
            printf("No\n");
        }
    }
}

例题3:HDU 5036

题意:一个人要打开或者用炸弹砸开所有的门,每个门里面有一些钥匙,一个钥匙对应一个门,有了一个门的钥匙就能打开相应的门,告诉每个门里面有哪些门的钥匙,问需要用的炸弹为多少。

我们考虑对于每一扇们单独计算期望,根据期望的线性性质最后累加起来就是答案。

分析:利用 bitset 优化 floyed 传递闭包 (利用 bitset 优化计算个数的过程)

就是不需要用到三重循环,而是把一个节点的父亲节点的所有父亲节点累计在这个孙子 bitset 上。

(即如果一个点是另一个点的父亲,那么父亲的父亲也都能够到达这个点,那就可以全部记录在这个孙子 bitset 上了 )

#include <cstdio>
#include <cstring>
#include <bitset>
using namespace std;

const int maxn = 1e3+3;
bitset<maxn> a[maxn];

int main(){
    int T,kase=1;
    scanf("%d",&T);
    while(T--){
        int n,x,y;
        scanf("%d",&n);
        for(int i=1; i<=n; i++) a[i].reset();
        for(int i=1; i<=n; i++){
            a[i].set(i);
            scanf("%d",&x);
            for(int j=1; j<=x; j++){
                scanf("%d",&y);
                a[y].set(i);
            }
        }
        for(int i=1; i<=n; i++){
            for(int j=1; j<=n; j++){
                if(a[j].test(i)){
                    a[j] |= a[i];
                }
            }
        }
        double ans = 0;
        for(int i=1; i<=n; i++){
            ans += 1.0/(a[i].count());
            // printf("%d %lf\n", i,ans);
        }
        printf("Case #%d: %.5lf\n",kase++, ans);
    }
}

 

posted @ 2019-09-09 01:33  *Zzz  阅读(952)  评论(0编辑  收藏  举报