【CF113D】Museum【概率期望】【高斯消元】
題意:一張 nnn 個點的無向連通圖,兩個人開始時分別在 a,ba,ba,b。每次在 uuu 時會以 ppp 的概率原地不動,1?p1-p1?p 的概率等概率隨機選擇到一個相鄰的點,當兩人在同一點時停止。分別求在每個點相遇的概率。
n≤22n\leq 22n≤22
網上一堆 “從起點走到 (i,j)(i,j)(i,j) 的概率”,看得我一臉懵逼……
很容易分析出轉移矩陣 MMM,然后相當于求這個東西:
lim?t→+∞MtV\lim_{t\to +\infin}M^{t}Vt→+∞lim?MtV
但這個并沒有通用的求法,因為矩陣的特征向量有無數多個。
算法一
比較直觀的解法。
設 f(i,j)f(i,j)f(i,j) 表示 (i,j)(i,j)(i,j) 這個狀態到達次數的期望,即這個狀態在所有世界線中出現次數的平均值。
由于最終點只有可能出現 000 次或 111 次,所以它的期望次數就是概率。
而這個期望隨便消一下就可以算出來。
算法二
比較本質的解法。
考慮枚舉一個最終狀態 (s,s)(s,s)(s,s),在此條件下求 f(i,j)f(i,j)f(i,j) 表示最終到這個狀態的概率,令 f(i,i)=[i=s]f(i,i)=[i=s]f(i,i)=[i=s],就可以消元了。但這樣是 O(n7)O(n^7)O(n7) 的,無法通過。
考慮一次性把每個點作為終點的 nnn 個答案算出來,即構建出 (n2?n)×(n2)(n^2-n)\times (n^2)(n2?n)×(n2) 的矩陣。這樣有 n2n^2n2 個未知數但只有 n2?nn^2-nn2?n 個方程,無法解出,但可以求出 f(a,b)f(a,b)f(a,b) 關于 f(1,1),f(2,2),…,f(n,n)f(1,1),f(2,2),\dots,f(n,n)f(1,1),f(2,2),…,f(n,n) 的線性表達,就可以求出答案了。
復雜度 O(n6)O(n^6)O(n6)
所以算法一算法二以及上面那個假算法寫出來都一樣的……
#include <iostream> #include <cstdio> #include <cstring> #include <cctype> #include <cmath> #include <vector> using namespace std; vector<int> e[25]; double p[25],a[505][505]; int n,m,sa,sb; inline int id(int x,int y) {if (x==y) return n*n-n+x;return (x-1)*(n-1)+y-(y>x); } void gauss(int n,int m) {for (int i=1;i<=n;i++){int pos=i;for (int j=i+1;j<=n;j++) if (fabs(a[j][i])>fabs(a[pos][i])) pos=j;if (pos>i) swap(a[i],a[pos]);for (int j=1;j<=n;j++)if (j!=i){double t=a[j][i]/a[i][i];for (int k=i;k<=m;k++)a[j][k]-=t*a[i][k];}} } int main() {scanf("%d%d%d%d",&n,&m,&sa,&sb);if (sa==sb){for (int i=1;i<=n;i++) if (i==sa) printf("%.10f ",1.0);else printf("%.10f ",0.0);return 0;}for (int i=1;i<=m;i++){int u,v;scanf("%d%d",&u,&v);e[u].push_back(v),e[v].push_back(u);}for (int i=1;i<=n;i++) scanf("%lf",&p[i]);for (int u=1;u<=n;u++)for (int v=1;v<=n;v++)if (u!=v){int s=id(u,v);double pu=1.0/e[u].size(),pv=1.0/e[v].size();for (int i=0;i<=(int)e[u].size();i++)for (int j=0;j<=(int)e[v].size();j++){double t=(i<(int)e[u].size()? (1-p[u])*pu:p[u])*(j<(e[v].size())? (1-p[v])*pv:p[v]);a[s][id(i<(int)e[u].size()? e[u][i]:u,j<(int)e[v].size()? e[v][j]:v)]=t;}a[s][s]-=1;}gauss(n*n-n,n*n);int s=id(sa,sb);for (int i=n*n-n+1;i<=n*n;i++) printf("%.10f ",-a[s][i]/a[s][s]);return 0; }總結
以上是生活随笔為你收集整理的【CF113D】Museum【概率期望】【高斯消元】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【WC2019】数树【子集反演】【结论】
- 下一篇: 【SDOI2017】硬币游戏【KMP】【