1. 程式人生 > >Luogu4745/Gym101620G CERC2017 Gambling Guide 期望、DP、最短路

Luogu4745/Gym101620G CERC2017 Gambling Guide 期望、DP、最短路

ostream max guid head def int http tst return

傳送門——Luogu

傳送門——Vjudge


\(f_x\)為從\(x\)走到\(N\)的期望步數

如果沒有可以不動的限制,就是隔壁HNOI2013 遊走

如果有可以不動的限制,那麽\(f_x = \frac{\sum\limits_{(x,y) \in e} \min(f_x , f_y)}{du_x} + 1\)。可以發現如果存在\(f_y < f_x\)\(f_y\)就會對\(f_x\)產生貢獻。類似於最短路松弛的過程,可以堆優化Dijkstra。

將式子化簡一下,得到\(f_x = \frac{du_x + \sum\limits_{(x,y) \in e} [f_y < f_x]f_y}{\sum\limits_{(x,y) \in e} [f_y < f_x]}\)

,那麽就可以動態計算\(f_x\)的值。

值得註意的是為什麽在當前情況下\(f_y\)松弛一個比\(f_y\)大的\(f_x\)是正確的。給出一個簡陋的數學證明:不妨設\(f_y = f_x - \Delta (\Delta > 0)\),又設\(f_y\)松弛\(f_x\)之後得到\(f_x'\),將\(f_x\)\(f_x'\)代入上面的求\(f_x\)得式子,可以得到\(f_x - f_x' = \frac{\Delta}{\sum\limits_{(x,y) \in e} [f_y < f_x](1 + \sum\limits_{(x,y) \in e} [f_y < f_x])}\)

,所以\(0 < f_x - f_x' < f_y - f_x\),即\(f_x < f_x' < f_y\),所以不會出現松弛之後\(f_x'\)變大或者變得比\(f_y\)小的情況。

#include<iostream>
#include<cstdio>
#include<cctype>
#include<algorithm>
#include<cstring>
#include<queue>
//This code is written by Itst
using namespace std;

inline int read(){
    int a = 0;
    char c = getchar();
    while(!isdigit(c)) c = getchar();
    while(isdigit(c)){
        a = a * 10 + c - 48;
        c = getchar();
    }
    return a;
}

#define ld long double
#define PDI pair < ld , int >
#define st first
#define nd second
const int MAXN = 3e5 + 7;
struct Edge{
    int end , upEd;
}Ed[MAXN << 1];
int head[MAXN] , in[MAXN] , cnt[MAXN];
int N , M , cntEd;
ld p[MAXN];
priority_queue < PDI > q;
bool vis[MAXN];

inline void addEd(int a , int b){
    Ed[++cntEd] = (Edge){b , head[a]};
    head[a] = cntEd;
    ++in[b];
}

void Dijk(){
    q.push(PDI(0 , N));
    while(!q.empty()){
        PDI t = q.top(); q.pop();
        if(vis[t.nd]) continue;
        vis[t.nd] = 1; p[t.nd] = -t.st;
        for(int i = head[t.nd] ; i ; i = Ed[i].upEd)
            if(!vis[Ed[i].end]){
                ++cnt[Ed[i].end];
                p[Ed[i].end] += p[t.nd];
                q.push(PDI(-(p[Ed[i].end] + in[Ed[i].end]) / cnt[Ed[i].end] , Ed[i].end));
            }
    }
}

int main(){
#ifndef ONLINE_JUDGE
    freopen("in","r",stdin);
    //freopen("out","w",stdout);
#endif
    N = read(); M = read();
    for(int i = 1 ; i <= M ; ++i){
        int a = read() , b = read();
        addEd(a , b); addEd(b , a);
    }
    Dijk(); printf("%.8Lf" , p[1]);
    return 0;
}

Luogu4745/Gym101620G CERC2017 Gambling Guide 期望、DP、最短路