http://acm.hdu.edu.cn/showproblem.php?pid=5036
每个房间打开有两种方式:被炸开或由其它房间里的钥匙打开。其它房间的钥匙有可能是直接打开该房间也有可能间接打开该房间。所以这个房间被炸开的概率是1/所有能打开该房间的方法,那么最后的期望就是这些概率之和。
看的题解,用bitset记录所有能打开该房间的那些房间,相当于做传递闭包运算。
#include <stdio.h>
#include <iostream>
#include <map>
#include <set>
#include <bitset>
#include <list>
#include <stack>
#include <vector>
#include <math.h>
#include <string.h>
#include <queue>
#include <string>
#include <stdlib.h>
#include <algorithm>
#define LL __int64
//#define LL long long
#define eps 1e-9
#define PI acos(-1.0)
using namespace std;
const int INF = 0x3f3f3f3f;
const int mod = 10000007;
bitset<1010>key[1010];
int main()
{
int test;
scanf("%d",&test);
for(int item = 1; item <= test; item++)
{
int n,k,num;
scanf("%d",&n);
for(int i = 0; i < n; i++)
key[i].reset();
for(int i = 0; i < n; i++)
{
key[i][i] = 1;
scanf("%d",&k);
for(int j = 0; j < k; j++)
{
scanf("%d",&num);
key[i][num-1] = 1;
}
}
for(int j = 0; j < n; j++)
{
for(int i = 0; i < n;i++)
{
if(key[i][j])
key[i] |= key[j]; //传递闭包
}
}
double ans = 0;
for(int i = 0; i < n; i++)
{
int cnt = 0;
for(int j = 0; j < n; j++)
{
if(key[j][i])
cnt++;
}
ans += 1.0/cnt;
}
printf("Case #%d: %.5lf\n",item,ans);
}
return 0;
}