Description
有一天Petya和他的朋友Vasya在进行他们众多旅行中的一次旅行,他们决定去参观一座城堡博物馆。这座博物馆有着特别的样式。它包含由m条走廊连接的n间房间,并且满足可以从任何一间房间到任何一间别的房间。
两个人在博物馆里逛了一会儿后两人决定分头行动,去看各自感兴趣的艺术品。他们约定在下午六点到一间房间会合。然而他们忘记了一件重要的事:他们并没有选好在哪儿碰面。等时间到六点,他们开始在博物馆里到处乱跑来找到对方(他们没法给对方打电话因为电话漫游费是很贵的)
不过,尽管他们到处乱跑,但他们还没有看完足够的艺术品,因此他们每个人采取如下的行动方法:每一分钟做决定往哪里走,有Pi 的概率在这分钟内不去其他地方(即呆在房间不动),有1-Pi 的概率他会在相邻的房间中等可能的选择一间并沿着走廊过去。这里的i指的是当期所在房间的序号。在古代建造是一件花费非常大的事,因此每条走廊会连接两个不同的房间,并且任意两个房间至多被一条走廊连接。
两个男孩同时行动。由于走廊很暗,两人不可能在走廊碰面,不过他们可以从走廊的两个方向通行。(此外,两个男孩可以同时地穿过同一条走廊却不会相遇)两个男孩按照上述方法行动直到他们碰面为止。更进一步地说,当两个人在某个时刻选择前往同一间房间,那么他们就会在那个房间相遇。
两个男孩现在分别处在a,b两个房间,求两人在每间房间相遇的概率。
第一行包含四个整数,n表示房间的个数;m表示走廊的数目;a,b (1 ≤ a, b ≤ n),表示两个男孩的初始位置。
之后m行每行包含两个整数,表示走廊所连接的两个房间。
之后n行每行一个至多精确到小数点后四位的实数 表示待在每间房间的概率。
题目保证每个房间都可以由其他任何房间通过走廊走到。
Output
输出一行包含n个由空格分隔的数字,注意最后一个数字后也有空格,第i个数字代表两个人在第i间房间碰面的概率(输出保留6位小数)
注意最后一个数字后面也有一个空格
2 1 1 2
1 2
0.5
0.5
Sample Output
0.500000 0.500000
HINT
对于100%的数据有 n <= 20,n-1 <= m <= n(n-1)/2
Source
高斯消元
Solution
有一个非常妙的东西,就是在博物馆i碰头的概率=两个人都在博物馆i的期望次数/总碰头次数,这题总碰头次数=1,因此两个人都在i的期望次数就是答案。
记\(f_{i,j}\)表示A在i,B在j的期望次数。
列出转移,放到矩阵中 用神奇的高斯去消。
注意\(f_{S,T}\)要多加1,因为一开始算一次。
和的期望等于期望的和。
Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
| #include <cmath>
#include <cstdio>
#include <algorithm>
using namespace std;
const double one = 1;
const double eps = 1e-10;
double a[405][405], P[25];
int n, m, S, T, tot, cnte, h[25], id[25][25], D[25];
struct edge_t { int to, next; } edge[100005];
inline int getint() {
int r = 0; bool z = true; char c = getchar();
for (; c < '0' || c > '9'; c = getchar()) if (c == '-') z = false;
for (; '0' <= c && c <= '9'; c = getchar()) r = r * 10 - '0' + c;
if (z) return r;
return -r;
}
void ins(int x, int y) {
edge[++cnte].to = y;
edge[cnte].next = h[x];
h[x] = cnte;
}
void build(int u, int v) {
int x = id[u][v], y; --a[x][x];
for (int i = h[u]; i; i = edge[i].next)
for (int j = h[v]; j; j = edge[j].next) {
int tu = edge[i].to, tv = edge[j].to;
if (tu == tv) continue; y = id[tu][tv];
if (tu == u && tv == v) a[x][y] += P[tu] * P[tv];
else if (tu == u) a[x][y] += P[tu] * (one - P[tv]) / double(D[tv]);
else if (tv == v) a[x][y] += P[tv] * (one - P[tu]) / double(D[tu]);
else a[x][y] += (one - P[tu]) * (one - P[tv]) / double(D[tu]) / double(D[tv]);
}
}
void Gauss() {
int pos;
for (int i = 1; i < tot; ++i) {
for (int j = i; j <= tot; ++j) if (fabs(a[j][i]) > eps) {pos = j; break;}
if (i != pos) for (int j = 1; j <= tot+1; ++j) swap(a[i][j], a[pos][j]);
for (int j = 1; j <= tot; ++j) {
if (j == i || fabs(a[j][i]) <= eps) continue;
double tmp = a[j][i] / a[i][i];
for (int k = 1; k <= tot + 1; ++k) a[j][k] -= tmp * a[i][k];
}
}
}
int main() {
n = getint(); m = getint(); S = getint(); T = getint();
for (int i = 0; i < m; ++i) {
int x = getint(), y = getint();
ins(x, y); ins(y, x);
++D[x]; ++D[y];
}
for (int i = 1; i <= n; ++i) {
ins(i, i);
scanf("%lf", P + i);
for (int j = 1; j <= n; ++j) id[i][j] = ++tot;
}
a[id[S][T]][tot+1] = -one;
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n; ++j)
build(i, j);
Gauss();
for (int i = 1; i <= n; ++i) {
int x = id[i][i];
printf("%.6lf ", a[x][tot+1] / a[x][x]);
}
}
|