【bitset模板题】HDU 5036 Explosion

题意:
一个人要打开或者用炸弹砸开所有的门,每个门里面有一些钥匙,一个钥匙对应一个门,有了一个门的钥匙就能打开相应的门,告诉每个门里面有哪些门的钥匙,问用的炸弹为期望值。
 
分析:
期望值 = 每个门用炸弹炸开的概率之和
而 每个门用炸弹炸开的概率 = 1 / 到达这个门的方案数, 因为炸开门的方案只有一种
我们用bitset记录门间的联通情况,求出方案数即可
 
我们开一个bitset数组 a
       假如  a[i] = 0  1  0  1  1  0  1          即 i 号门能到 1 3 4 6 号门
                a[j] = 1  0  0  1  0  1  0
如果 j 能到 i ,那么 j 本来能到的现在还能到, i 能到的 j 也能到
也就是我们把   a[j] |= a[i] 即可
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <bitset>
using namespace std;
const int maxn = 1005;
bitset<maxn> a[maxn];
int main() {
    int t; scanf("%d", &t);
    for(int cnt=1; cnt<=t; cnt++){
        int n; scanf("%d", &n);
        for(int i=0; i<n; i++){ 
            a[i].reset();       //这里记得初始化
            a[i][i] = 1;       //自己到自己是联通的
        }
        for(int i=0; i<n; i++){
            int k; scanf("%d", &k);
            while(k--){
                int x; scanf("%d", &x);
                a[i][--x] = 1;//我们的下标统一从0开始,所以 --x
            }
        }
        for(int i=0; i<n; i++){
            for(int j=0; j<n; j++){
                if(a[j][i]) a[j] |= a[i]; //i能到达的j也能到达
            }
        }
        double ans = 0;
        int tot = 0;
        for(int i=0; i<n; i++){
            tot = 0;
            for(int j=0; j<n; j++){
                if(a[j][i]) tot ++;//求方案数
            }
            ans += 1.0/tot; //更新期望值
        }
        printf("Case #%d: %.5lf\n", cnt, ans);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/hzoi-poozhai/p/12681300.html