HDU 4418 Time travel
概率 Markov链 高斯消元
http://acm.hdu.edu.cn/showproblem.php?pid=4418
题意不太好懂……
一个人在数轴上来回走,每次以一定概率前进[1, M]步,如果停下来的地方是目标就终止,否则继续该过程直到在目标停下。求走过的路程的期望。
读明白了就可以发现其实是个比较明显的概率高斯消元题。
首先把(pos,dir)全部展开成一维的坐标,把往回走的方向翻折到另一边即可。这样就有2*(N-1)个点。
令K=2*(N-1),写出期望方程
e[pos] = sigma{i from 1 to m} (e[(pos+i)%K]+i)*p[i]
边界为e[t]=e[(K-t)%K]=0。
高斯消元解之求e[s]即可。但是tricky的地方就在这里。看以下这组数据:
4 2 2 0 -1
0 100
答案应该为2,而高斯消元解出来的结果是no solution。原因就在于有些状态从s开始走是根本访问不到的,同时也访问不到t,也就是这些状态和整个markov过程根本无关。这些状态之间构成的方程无解就会导致整个解向量不存在,但并不代表e[s]不存在。解决的办法就是将这些状态的期望强制设为INF。判断某个状态能否访问到用bfs就可以了。
#include <iostream> #include <cassert> #include <cmath> #include <cstdio> #include <cstring> #include <queue> #include <algorithm> using namespace std; const double EPS = 1e-8; inline int sgn(double d) { if (fabs(d)<EPS) return 0; return d>0?1:-1; } int gauss(int N, int M, double a[][222]) { int i, j, r, c, pvt; double maxp; for (r=0, c=0; r<N && c<M; ++r, ++c) { for (maxp=0, i=r; i < N; ++i) if (fabs(a[i][c])>fabs(maxp)) maxp = a[pvt=i][c]; if (sgn(maxp)==0) { r--; continue; } if (pvt != r) for (j = r; j <= M; ++j) swap(a[r][j], a[pvt][j]); for (j = c+1; j <= M; ++j) { a[r][j] /= maxp; for (i = r+1; i < N; ++i) a[i][j] -= a[i][c]*a[r][j]; } } for (i = r; i < N; ++i) if (sgn(a[i][M])) return -1; if (r < M) return M-r; for (i = M-1; i >= 0; --i) for (j = i+1; j < M; ++j) a[i][M] -= a[j][M]*a[i][j]; return 0; } int T, N, M, s, t, d; double a[222][222]; double p[111]; int vis[222]; bool bfs(int s) { queue<int> q; q.push(s); memset(vis, 0, sizeof vis); vis[s] = 1; while (!q.empty()) { int u = q.front(); q.pop(); for (int i = 0; i < M; ++i) { u++; if (u==N) u = 0; if (sgn(p[i]) && !vis[u]) { vis[u] = 1; q.push(u); } } } if (vis[t] || vis[(N-t)%N]) return 1; else return 0; } int main() { int i, j, k, r, c; cin>>T; while (T--) { cin>>N>>M>>t>>s>>d; assert(N!=0); for (i = 0; i < M; ++i) { cin>>p[i]; p[i] /= 100; } N = N-1<<1; if (d > 0) s = N-s; if (s==t) { puts("0.00"); continue; } if (!bfs(s)) { puts("Impossible !"); continue; } double sum = 0; for (i = 0; i < M; ++i) sum += p[i]*(i+1); memset(a, 0, sizeof a); for (i = 0; i < N; ++i) { a[i][i] = 1; if (!vis[i]) { a[i][N] = 1e9; continue; } if (i==t||i==(N-t)%N) { a[i][N] = 0; continue; } a[i][N] = sum; int now = i; for (j = 0; j < M; ++j) { now++; if (now==N) now = 0; a[i][now] -= p[j]; } } if (~gauss(N, N, a)) { printf("%.2f\n", a[s][N]+EPS); } else puts("Impossible !"); } return 0; }