機率DP

all_for_god發表於2024-10-23
  • 機率DP是DP中一個非常重要且較難的DP型別。其題型靈活多變,尤其愛與樹形DP結合,同時很可能需要各種資料結構最佳化。
  • 其主要考點便是DP方程的建立與維護。由於“機率”二字,許多時候分類討論與小數運算也是不可避免的。
    因此,機率DP對選手的邏輯思維與程式碼能力也有很高的要求,可以說是DP中的集大成者。

P2081 [NOI2012] 迷失遊樂園

  • 題意:給定一顆有 \(n\) 個點的樹或基環樹,每條邊有邊權 \(w_i\)
    求從每個點開始,在樹上隨機不重地走,最後的期望經過的邊權和。
    對於每個節點,其下一步走到其任意相鄰點的機率是相同的。
  • 資料範圍 \(n\le 1e5,w_i \le 100\)

普通樹

先考慮在普通的樹上怎麼做。假設我們先欽定 \(rt\) 為根節點,那麼對於每個除根以外的節點,其第一步的走法有兩種:

  1. 向父親走
  2. 向兒子走
    容易發現,如果我們已經求出這個點所有兒子再向下走的機率,那這個點向兒子走的機率轉移是樸素的。
    設第一步向下走的期望權值為 \(down_u\),則有

\[{\Large down_u=\frac{\sum_vdown_v+w_{u,v}}{son_u}} \]

  • 其中 \(son_u\) 代表 \(u\) 的兒子個數,\(v\) 代表 \(u\) 的某一個兒子。
    而向父親走的情況稍微複雜了一點。由於這個點走向父親後還能再向其其他兒子走,也可以繼續向上,因此情況要考慮完全
    \(u\) 第一步向上的期望權值 為 \(up_u\),則有

\[{\Large up_u=w_{u,k}+\frac{up_k\cdot fa_k+down_k\cdot son_k-down_u-w_{u,k}}{son_k+fa_k-1}} \]

  • 其中 \(k\)\(u\) 的父親,\(fa_k\)\(k\) 父親的數量。這聽起來可能有些奇怪,因為普通樹只有一個或沒有父親。
    不過在一會要討論的基環樹中,\(fa_u\) 就能體現出作用
  • \(up_k\cdot fa_k\) 是繼續向上走的貢獻,\(down_k\cdot son_k\)\(k\) 又向下走的貢獻。
    但因為不能重複走到 \(u\) 點,因此需要減去貢獻。注意上面是總的貢獻,因此可以直接減
    最後,因為不能走回 \(u\),因此總共有 \(son_k+fa_k-1\) 種情況。
  • 由於 \(up_u\) 需要由 \(down_u\)\(down_k\) 推出,因此對於普通樹,先求 \(down\) 再求 \(up\) 即可。
    但需要注意根節點沒有父親,因此處理 \(up\) 時,注意從根節點的所有兒子開始處理。
點選檢視程式碼
void make_down(int u,int k)
{
	for(int i=0;i<tot[u];i++)
	{
		int v=q[u][i].v;if(vis[v]||v==k) continue;
		fa[v]=1;make_down(v,u);son[u]++;down[u]+=1.0*(down[v]+q[u][i].w);
	}
	if(son[u]) down[u]=down[u]/son[u];
}
void make_up(int u,int k,ld w)
{
	up[u]=w;
	if(fa[k]+son[k]-1)
	up[u]=up[u]+(up[k]*fa[k]+down[k]*son[k]-down[u]-w)/(son[k]+fa[k]-1);
	for(int i=0;i<tot[u];i++){
		int v=q[u][i].v;if(v==k||vis[v]) continue;
		make_up(v,u,q[u][i].w);
	}
}
void work1()
{
	make_down(1,0);
	for(int i=0;i<tot[1];i++) make_up(q[1][i].v,1,q[1][i].w);
}

基環樹

  • 可以先畫個圖。
    基環樹
  • 紅邊是環上的邊。可以發現,如果我們將紅邊刪掉,就是一片森林。因此對

相關文章