CF113D Museum(概率 + 高斯消元法)

Description

n n 个点 m m 条边的无重边连通图,初始两个人在点 a a b b 。每一单位时间,假设两个人在点 i i j j 那么有 p i p_i p j p_j 的概率原地不动,有 1 p i 1 - p_i 1 p j 1 - p_j 的概率等概率移动到相邻的点。求两个人在每个点相遇的概率,只要相遇那么停止移动。

1 n 22 1 \leq n \leq 22

Solution

f i , j f_{i,j} 为两个人在 i i j j 的概率, f a , b = 1 f_{a,b} = 1 。那么每个点有一个人动,一个人不动,两个人一起动或都不动分类讨论一下。令 d i d_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}}

那么有 n 2 n^2 个未知数,用高斯消元法解方程复杂度为 O ( n 6 ) O(n^6)

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;
}

猜你喜欢

转载自blog.csdn.net/qq_39984146/article/details/105021924