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

传送门


\(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_x - f_y\),即\(f_x > f_x' > f_y\),所以不会出现松弛之后\(f_x'\)变得比\(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;
}
posted @ 2019-03-03 22:24  cjoier_Itst  阅读(377)  评论(3编辑  收藏  举报