Loading

ABC144_F Fork in the Road 期望DP

# ABC144_F Fork in the Road 期望DP

## 题意

有$N$个点,$M$条有向边,有向边表示$s_i -> t_i$,且满足$s_i < t_i$

每到一个点会等概率得选择一条边移动

在开始前会删除一条边(或者不删)来最小化到$n$的期望步数

问移动到$N$号点的期望步数
$$
2\leq N\leq600\\
N - 1\leq M \leq \frac{N(N-1)}{2}
$$


## 分析

有一些显然的结论

设$F[i]$表示从$i$号点走到$n$号点的期望步数,则有
$$
F[n] = 0\\
F[i] = avg(F[j]) + 1 (i,j)有边
$$
这样就构成方程组高斯消元即可

注意到此题给出$s_i < t_i$

即保证了总是从小点走到大点,因此可以直接DP

那么删哪条边呢?

从转移方程来看,我们显然希望删除掉最大的$F[j]$来最小化当前的期望,而此题的$n$比较小,因此不妨枚举删除$i$出发的边,贪心删除最大期望的边

复杂度$O(n^2m)$

## 代码

```c++
double dp[605];
vector<int> e[maxn];
int n,m;
 
double cal(int x){
	for(int i = n - 1;i >= 1;i--){
		dp[i] = 1;
		double mx = -1;
		double t = 0;
		for(auto v:e[i]){
			if(dp[v] > mx) mx = dp[v],t = v;
		}
		if(i == x && e[i].size() != 1)
		for(auto v:e[i]) {
			if(v == t) continue;
			dp[i] += dp[v] / (e[i].size() - 1);
		} 
		else
		for(auto v:e[i])
			dp[i] += dp[v] / e[i].size();
	}
	return dp[1];
}

int main(){
	n = rd();
	m = rd();
	for(int i = 1;i <= m;i++){
		int x = rd();
		int y = rd();
		e[x].push_back(y);
	}
	dp[n] = 0;
	double ans = 1e18;
	for(int i = 1;i < n;i++){
		ans = min(ans,cal(i));
	}
	printf("%.10f",ans);
}
posted @ 2021-02-08 21:28  MQFLLY  阅读(189)  评论(0编辑  收藏  举报