Explosion
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 869 Accepted Submission(s): 303
Problem Description
Everyone knows Matt enjoys playing games very much. Now, he is playing such a game. There are N rooms, each with one door. There are some keys(could be none) in each room corresponding to some doors among these N doors. Every key can open only one door. Matt has some bombs, each of which can destroy a door. He will uniformly choose a door that can not be opened with the keys in his hand to destroy when there are no doors that can be opened with keys in his hand. Now, he wants to ask you, what is the expected number of bombs he will use to open or destroy all the doors. Rooms are numbered from 1 to N.
Input
The first line of the input contains an integer T, denoting the number of testcases. Then T test cases follow.
In the first line of each test case, there is an integer N (N<=1000) indicating the number of rooms.
The following N lines corresponde to the rooms from 1 to N. Each line begins with an integer k (0<=k<=N) indicating the number of keys behind the door. Then k integers follow corresponding to the rooms these keys can open.
Output
For each test case, output one line "Case #x: y", where x is the case number (starting from 1), y is the answer which should be rounded to 5 decimal places.
Sample Input
Sample Output
Case #1: 1.00000
Case #2: 3.00000
Source
2014 ACM/ICPC Asia Regional Beijing Online
题意是有n扇门,每扇门后面都有几个钥匙,每个钥匙对应一扇门。如果没有钥匙可以炸开一扇门。问需要打开所有的门所需的最少的炸门次数。
bitset真是强大啊。一个n^3的算法居然也可以过,只能说新姿势get。貌似是优化了常数(n/8? n/32?)。
炸开第i扇门的概率是1/k,k表示能够到达i的门的数量,这个到达有传递闭包的性质,本来需要n^3类似于floyd算法一样枚举,然后用bitset可以轻松减少运行时间~~
#include <iostream>
#include <cmath>
#include <cstdlib>
#include <time.h>
#include <stack>
#include <cstring>
#include <bitset>
using namespace std;
#define maxn 1111
bitset <maxn> g[maxn];
int n, k, v;
int main () {
//freopen ("in", "r", stdin);
int t, kase = 0;
scanf ("%d", &t);
while (t--) {
printf ("Case #%d: ", ++kase);
scanf ("%d", &n);
for (int i = 1; i <= n; i++) {
g[i].reset ();
g[i][i] = 1;
}
for (int u = 1; u <= n; u++) {
scanf ("%d", &k);
for (int j = 1; j <= k; j++) {
scanf ("%d", &v);
g[u][v] = 1;
}
}
for (int j = 1; j <= n; j++) {
for (int i = 1; i <= n; i++) {
if (g[i][j])
g[i] |= g[j];
}
}
double ans = 0.0;
for (int i = 1; i <= n; i++) {
double num = 0.0;
for (int j = 1; j <= n; j++) {
if (g[j][i])
num += 1.0;
}
ans += 1.0/num;
}
printf ("%.5f\n", ans);
}
return 0;
}