Description
有 个点 条边的无重边连通图,初始两个人在点 和 。每一单位时间,假设两个人在点 和 那么有 和 的概率原地不动,有 和 的概率等概率移动到相邻的点。求两个人在每个点相遇的概率,只要相遇那么停止移动。
。
Solution
令 为两个人在 和 的概率, 。那么每个点有一个人动,一个人不动,两个人一起动或都不动分类讨论一下。令 为点 的度数。转移为
那么有 个未知数,用高斯消元法解方程复杂度为 。
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;
}