Description
有 n n n 个点 m m m 条边的无重边连通图,初始两个人在点 a a a 和 b b b。每一单位时间,假设两个人在点 i i i 和 j j j 那么有 p i p_i pi 和 p j p_j pj 的概率原地不动,有 1 − p i 1 - p_i 1−pi 和 1 − p j 1 - p_j 1−pj 的概率等概率移动到相邻的点。求两个人在每个点相遇的概率,只要相遇那么停止移动。
1 ≤ n ≤ 22 1 \leq n \leq 22 1≤n≤22。
Solution
令 f i , j f_{i,j} fi,j 为两个人在 i i i 和 j j j 的概率, f a , b = 1 f_{a,b} = 1 fa,b=1。那么每个点有一个人动,一个人不动,两个人一起动或都不动分类讨论一下。令 d i d_i di 为点 i i i 的度数。转移为
f i , j = f i , j × p i p j + f i , k × p i ∑ j → k 1 − p k d k + f k , j × p j × ∑ i → k 1 − p k d k + f k 1 , k 2 × ∑ i → k 1 ∑ j → k 2 1 − p k d k 1 1 − p k 2 d k 2 f_{i,j} = \\ f_{i,j} \times p_i p_j +\\ f_{i,k} \times p_i \sum_{j \to k} \frac{1 - p_k}{d_k} + \\ f_{k,j} \times p_j \times \sum_{i \to k} \frac{1 - p_k}{d_k} + \\ f_{k_1,k_2} \times \sum_{i \to k_1} \sum_{j \to k_2} \frac{1 - p_k}{d_{k_1}} \frac{1 - p_{k_2}}{d_{k_2}} fi,j=fi,j×pipj+fi,k×pij→k∑dk1−pk+fk,j×pj×i→k∑dk1−pk+fk1,k2×i→k1∑j→k2∑dk11−pkdk21−pk2
那么有 n 2 n^2 n2 个未知数,用高斯消元法解方程复杂度为 O ( n 6 ) O(n^6) O(n6)。
Code
#include <bits/stdc++.h>
using namespace std;
const int N = 500 + 5, INF = 0x3f3f3f3f;
inline int read() {
int x = 0, f = 0; char ch = 0;
while (!isdigit(ch)) f |= ch == '-', ch = getchar();
while (isdigit(ch)) x = (x << 3) + (x << 1) + (ch ^ 48), ch = getchar();
return f ? -x : x;
}
vector <int> G[N];
double f[N][N], p[N];
int n, m, a, b, d[N];
int get(int i, int j) {
return (i - 1) * n + j;
}
void init() {
f[get(a, b)][n * n + 1] = 1;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++) {
int x = get(i, j); f[x][x] = 1;
if (i ^ j) f[x][x] -= p[i] * p[j];
for (auto y : G[j]) if (y ^ i) f[x][get(i, y)] -= p[i] * (1.0 - p[y]) / d[y];
for (auto y : G[i]) if (y ^ j) f[x][get(y, j)] -= p[j] * (1.0 - p[y]) / d[y];
for (auto y1 : G[i]) for (auto y2 : G[j]) if (y1 ^ y2) f[x][get(y1, y2)] -= (1.0 - p[y1]) * (1.0 - p[y2]) / d[y1] / d[y2];
}
}
void Gauss() {
for (int i = 1; i <= n * n; i++) {
int p = i;
while (!f[p][i] && p <= n * n) p++;
for (int j = 1; j <= n * n + 1; j++) swap(f[i][j], f[p][j]);
double x = f[i][i];
for (int j = 1; j <= n * n + 1; j++) f[i][j] /= x;
for (int j = 1; j <= n * n; j++)
if (i != j) {
x = f[j][i];
for (int k = 1; k <= n * n + 1; k++) f[j][k] -= f[i][k] * x;
}
}
}
int main() {
n = read(), m = read(), a = read(), b = read();
for (int i = 1; i <= m; i++) {
int x = read(), y = read();
G[x].push_back(y), G[y].push_back(x);
d[x]++, d[y]++;
}
for (int i = 1; i <= n; i++) scanf("%lf", &p[i]);
init(); Gauss();
for (int i = 1; i <= n; i++) printf("%lf ", f[get(i, i)][n * n + 1]);
return 0;
}