题意:
一个人要打开或者用炸弹砸开所有的门,每个门里面有一些钥匙,一个钥匙对应一个门,有了一个门的钥匙就能打开相应的门,告诉每个门里面有哪些门的钥匙,问用的炸弹为期望值。
分析:
期望值 = 每个门用炸弹炸开的概率之和
而 每个门用炸弹炸开的概率 = 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 ", cnt, ans); } return 0; }