1. 程式人生 > 實用技巧 >《演算法競賽進階指南》0x38概率與數學期望 綠豆蛙的歸宿

《演算法競賽進階指南》0x38概率與數學期望 綠豆蛙的歸宿

題目連結:https://www.acwing.com/problem/content/219/

題目給出一張有向無環圖,要求從1到n的路徑長度的數學期望,如果一個點有k條出邊,那麼走每條表的概率都是1/k,我們容易知道,記一個點x到終點n的路徑的數學期望是dis[x],那麼dis[x]計算的結果依賴於他所能到達的所有的邊,根據這個性質可以發現是跟拓撲排序有關係的,滿足這樣一種結構:在這個點處理之前它的所有可達的點都已經處理完了。

所以這個問題需要在拓撲排序的同時進行更新操作,需要建立反圖,建反圖是為了從可達點到該點進行更新。資訊的傳遞是從終點開始的,所以需要建立一張反圖進行反向遞推。

程式碼:

#include<iostream>
#include
<cstdio> #include<queue> using namespace std; const int maxn = 100010; int head[maxn],nxt[maxn*2],ver[maxn*2],len[maxn*2]; int n,m; int tot=0; int deg[maxn],out[maxn]; double dis[maxn];//記錄點i到n的路徑數學期望 void addedge(int u,int v,int w){ ver[++tot]=v; len[tot]=w; nxt[tot]=head[u]; head[u]
=tot; } int main(){ cin>>n>>m; int u,v,w; for(int i=1;i<=m;i++){ scanf("%d%d%d",&u,&v,&w); addedge(v,u,w);//建反圖 deg[u]++; out[u]++; } queue<int> q; q.push(n); while(q.size()){ int x=q.front(); q.pop();
for(int i=head[x];i;i=nxt[i]){ int y=ver[i]; dis[y]+=(dis[x]+(double)len[i])/deg[y]; if(--out[y]==0)q.push(y); } } printf("%.2lf\n",dis[1]); }