题意:有n个房间,每个房间都有k(0<=k<=n)把钥匙,你可以用炸弹炸开一扇门,获得房间里的钥匙。最初,你没有钥匙,当你手中没有钥匙时,你会随机炸一扇门,如果手中有钥匙,你会打开那扇门,获得其中钥匙,问当你打开所有的门,你使用炸弹的期望值。
分析:求打开所有门的总期望,可以先求每一扇门的期望,然后加起来。对于一扇门x,使用炸弹的期望只和这扇门的前导门有关(前导门为炸了前导门后,能够不使用钥匙就能打开x门)。设x的前导门数量为S。则门x的期望为1/(s+1)。这个可以用bitset处理。看到网上有用强连通分量处理,然后再用bitset。其实强连通分量处理一步并不能简化bitset运算。用强连通并无意义。
#include<bits/stdc++.h>
using namespace std;
const int N=1010;
bitset<N>k[N];
int main()
{
int cas=1,TA,n,x,y;
scanf("%d",&TA);
while(TA--)
{
scanf("%d",&n);
for(int i=0; i<n; i++)k[i].reset(),k[i][i]=true;
for(int i=0; i<n; i++)
{
scanf("%d",&x);
while(x--)
{
scanf("%d",&y);
k[i][y-1]=true;
}
}
for(int i=0; i<n; i++)
for(int j=0; j<n; j++)
if(k[j][i])
k[j]|=k[i];
double ans = 0.0;
for(int j=0; j<n; ++j)
{
int cnt=0;
for(int i=0; i<n; ++i)
if(k[i][j]) cnt++;
ans += 1.0 / cnt;
}
printf("Case #%d: %.5f\n",cas++,ans);
}
}