【BZOJ3270】博物馆
题意:给定一张无向连通图,两个人初始各在某个点上,每个时刻每个人会不动或任选出边走,求两人最终期望在哪里相遇
PoPoQQQ的解法:http://blog.csdn.net/popoqqq/article/details/44777907
我的解法
状态表示为f[k][i][j] 表示第K步第一人在i第二人在j
按步数划分阶段,对于每个阶段f[k][i][j]可以由f[k - 1][p][q]推出来
要求的东西是 sigma i = 1..oo (f[i][V][V])
所以可以把所有阶段的方程(矩阵)直接加起来,消去阶段(步数)这一维
对于K=1 方程只有一行 1= f[a][b]
最后的方程形如
for_each (i, j)
for_each (k, l)
sigma p[(k, l) to (i, j)] * x[k][l] = x[i][j]
特别的
for_each (k, l)
sigma p[(k, l) to (a, b)] * x[k][l] + 1 = x[a][b]
#include <cstdio> #include <cmath> #include <iostream> using namespace std; const int N = 410; int n, m, a, b; double map[N][N], p[N][N]; bool g[N][N]; int out[N]; void gauss(int n, double a[N][N]) { int i, j, k, r; for (i = 0; i < n; i ++) { r = i; for (j = i + 1; j < n; j ++) if (fabs(a[j][i]) > fabs(a[r][i])) r = j; if (r != i) for (j = 0; j <= n; j ++) swap(a[r][j], a[i][j]); for (k = i + 1; k < n; k ++) { double f = a[k][i] / a[i][i]; for (j = i; j <= n; j ++) a[k][j] -= f * a[i][j]; } } for (i = n - 1; i >= 0; i --) { for (j = i + 1; j < n; j ++) a[i][n] -= a[j][n] * a[i][j]; a[i][n] /= a[i][i]; } } int main() { scanf("%d%d%d%d", &n, &m, &a, &b); a --; b --; for (int i = 1, u, v; i <= m; i ++) { scanf("%d%d", &u, &v); u --; v --; g[u][v] = g[v][u] = 1; out[u] ++; out[v] ++; } for (int i = 0; i < n; i ++) scanf("%lf", &map[i][i]); for (int i = 0; i < n; i ++) for (int j = 0; j < n; j ++) { if (i == j) continue; if (g[i][j] == false) map[i][j] = 0; else map[i][j] = (1.0 - map[i][i]) / out[i]; } for (int i = 0; i < n; i ++) for (int j = 0; j < n; j ++) for (int k = 0; k < n; k ++) for (int l = 0; l < n; l ++) { int u = n * i + j; int v = n * k + l; if (k != l) p[u][v] = map[k][i] * map[l][j]; else p[u][v] = 0; } for (int i = 0; i < n * n; i ++) p[i][i] -= 1; p[n * a + b][n * n] = -1; gauss(n * n, p); for (int i = 0; i < n; i ++) printf("%.6lf ", p[n * i + i][n * n]); putchar(10); return 0; }