P4316 绿豆蛙的归宿(期望dp)

题目描述

给出张 n 个点 m 条边的有向无环图,起点为 11,终点为 n,每条边都有一个长度,并且从起点出发能够到达所有的点,所有的点也都能够到达终点。

绿豆蛙从起点出发,走向终点。 到达每一个顶点时,如果该节点有 k 条出边,绿豆蛙可以选择任意一条边离开该点,并且走向每条边的概率为 1/k。现在绿豆蛙想知道,从起点走到终点的所经过的路径总长度期望是多少?

错误点

  1. 题目给出的是有向边但是按无向边做处理;
  2. 直接遍历每种情况导致TL

思路

1.dfs找出每条可能的路径,在抵达终点后按照其概率赋值给终点(TL)
2.先由有向无环图推出解法大概会与拓扑排序有关,再结合期望dp的解法,可倒序求出每个位置的点到终点的期望长度,这里注意转移方程的写法:dp[u] += (dp[v] + w[u][v]) / cnt;(cnt表示由u到v的边数)

代码:

#include <iostream>
#include<vector>
#include<algorithm>
#include<cstring>
#include<set>
#include<queue>
using namespace std;
struct P {
	int to, v;
	P(int to, int v) :to(to), v(v) {}
};
vector<P>a[100005];
int n, cnt[100005],in[100005]; 
double dp[100005];
int main(void) {
	int m; cin >> n >> m; 
	while (m--) {
		int u, v, w;
		//倒序输入
		cin >> v >> u >> w;
		//单向边
		a[u].push_back(P(v, w));
		//v可往下走的边数
		cnt[v]++;
		in[v]++;
	}
	priority_queue<int>q; q.push(n); 
	//拓扑排序
	while (!q.empty()) {
		int x = q.top(); q.pop();
		for (int i = 0; i < a[x].size(); i++) {
		    int w = a[x][i].to;
			in[w]--; 
			//向上递推
			dp[w] += (dp[x] + a[x][i].v) / cnt[w];
			if (in[w] == 0) q.push(w); 
		}
	}
	printf_s("%.2lf\n", dp[1]);
	return 0;
}
posted @ 2023-04-27 17:05  mark0  阅读(40)  评论(0)    收藏  举报