【bzoj5197】[CERC2017]Gambling Guide 期望dp+堆优化Dijkstra
題目描述
給定一張n個(gè)點(diǎn),m條雙向邊的無(wú)向圖。 你要從1號(hào)點(diǎn)走到n號(hào)點(diǎn)。當(dāng)你位于x點(diǎn)時(shí),你需要花1元錢,等概率隨機(jī)地買到與x相鄰的一個(gè)點(diǎn)的票,只有通過(guò)票才能走到其它點(diǎn)。 每當(dāng)完成一次交易時(shí),你可以選擇直接使用那張票,也可以選擇扔掉那張票然后再花1元錢隨機(jī)買另一張票。注意你可以無(wú)限次扔票。 請(qǐng)使用最佳的策略,使得期望花的錢數(shù)最少。輸入
第一行包含兩個(gè)正整數(shù)n,m(1<=n,m<=300000),表示點(diǎn)數(shù)和邊數(shù)。 接下來(lái)m行,每行兩個(gè)正整數(shù)u,v(1<=u,v<=n),表示一條雙向邊。 輸入數(shù)據(jù)保證無(wú)重邊、無(wú)自環(huán),且1號(hào)點(diǎn)一定可以走到n號(hào)點(diǎn)。輸出
輸出一行一個(gè)實(shí)數(shù),即最少的期望花費(fèi),當(dāng)絕對(duì)或者相對(duì)誤差不超過(guò)10^{-6}時(shí)視為正確。樣例輸入
5 8
1 2
1 3
1 4
2 3
2 4
3 5
5 4
2 5
樣例輸出
4.1111111111
題解
期望dp+堆優(yōu)化Dijkstra
設(shè) $f[i]$ 表示 $i$ 到終點(diǎn)的期望步數(shù),那么有:$f[n]=0\ ,\ f[x]=\frac{\sum\limits_{(x,y)}\text{min}(f[x],f[y])+1}{d[x]}$ ,其中 $d[x]$ 表示 $x$ 的度數(shù)。
套路:對(duì)于這種 “初始只有一個(gè)點(diǎn)的dp值確定、其它點(diǎn)的dp值與其相鄰的點(diǎn)有關(guān)” 的圖上dp,考慮使用類似最短路的方式轉(zhuǎn)移。
初始的時(shí)候除了 $n$ 以外,每個(gè)點(diǎn)的 $\text{min}(f[x],f[y])$ 都取 $f[x]$ ,dp值為 $+\infty$ 。
然后從 $n$ 號(hào)點(diǎn)開(kāi)始最短路轉(zhuǎn)移:對(duì)于當(dāng)前的點(diǎn) $i$ ,如果某個(gè)相鄰的 $j$ 有 $f[j]>f[i]$ ,則對(duì)于 $f[j]$ 的計(jì)算來(lái)說(shuō),$\text{min}(f[j],f[i])$ 取 $f[i]$ 更優(yōu)。此時(shí)更新 $j$ 的dp值,并將 $j$ 加入到待用于更新其它點(diǎn)的集合中。
注意到:如果使用 $f[i]$ 將 $f[j]$ 更新為 $f'[j]$ ,那么顯然有 $f[i]\le f'[j]\le f[j]$ (等號(hào)在 $f[i]=f[j]$ 時(shí)取到),滿足堆優(yōu)化Dijkstra的貪心策略(當(dāng)前最小的一定不會(huì)再被更新到更小),因此可以使用dp值小根堆來(lái)維護(hù)待用于更新其它點(diǎn)的集合,使用類似堆優(yōu)化Dijkstra的方式轉(zhuǎn)移即可。
最終的答案就是 $f[1]$ 。
時(shí)間復(fù)雜度 $O(m\log n)$?
#include <queue> #include <cstdio> #include <algorithm> #define N 300010 using namespace std; typedef pair<double , int> pr; priority_queue<pr> q; double s[N] , f[N]; int head[N] , to[N << 1] , next[N << 1] , cnt , vis[N] , d[N] , c[N]; inline void add(int x , int y) {to[++cnt] = y , next[cnt] = head[x] , head[x] = cnt; } int main() {int n , m , i , x , y;scanf("%d%d" , &n , &m);for(i = 1 ; i <= m ; i ++ ) scanf("%d%d" , &x , &y) , add(x , y) , add(y , x) , d[x] ++ , d[y] ++ ;q.push(pr(0 , n));while(!q.empty()){x = q.top().second , q.pop();if(vis[x]) continue;vis[x] = 1;for(i = head[x] ; i ; i = next[i])if(!vis[to[i]])c[to[i]] ++ , s[to[i]] += f[x] , f[to[i]] = (s[to[i]] + d[to[i]]) / c[to[i]] , q.push(pr(-f[to[i]] , to[i]));}printf("%lf\n" , f[1]);return 0; }?
轉(zhuǎn)載于:https://www.cnblogs.com/GXZlegend/p/8507379.html
總結(jié)
以上是生活随笔為你收集整理的【bzoj5197】[CERC2017]Gambling Guide 期望dp+堆优化Dijkstra的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 基于 HTML5 Canvas 的交互式
- 下一篇: 用 Flask 来写个轻博客