P4316 绿豆蛙的归宿

题目传送门

这题是经典的期望dp题

要想做这道题,我们要先知道期望怎么算

若随机变量X的取值有x_1,x_2,\cdots,一个随机事件可表示为X=X_i,对应的概率为P(X=X_i)p_i。则称E(x)=\sum p_ix_i为随机变量X的数学期望,也就是说数学期望是随机变量取值与概率的乘积之和。

满足线性函数 E(ax+by)=aE(x)+bE(y)

我们再来说一下期望dp的模型

对于任意状态A,已知:

  1. 状态A所有的后继状态
  2. 设从状态A 转移到后继状态 B的概率 为 P(A,B),且\sum_{B}^{}P(A,B)=1
  3. 设从状态A转移到后继状态的B的花费为W(A,B)

求解:从起点状态S到终点状态T的期望花费

一般方法: 将状态视为图上的节点。

设E(A) 表示从状态A到终止状态T的期望花费。设E(T)=0

那么得到状态转移公式:

 当转移状态关系不成环时,状态转移为线性的。可以按照拓扑排序递推求解。

绿豆蛙的归宿

再看这道题,我们不妨设dp[i]为从i出发到达终点n的路径期望值。

G[i]为i所有的出边的集合

则:

同时又有一个问题,那就是转移时的过程怎么实现

不妨这样:既然是个DAG(有向无环图),那么我们可以倒着想

我们反向连边,进行一遍拓扑排序,在拓扑排序的时候进行期望dp的转移

 Code

#include <iostream>
#include <queue>
#include <vector>
#include <iomanip>
using namespace std;
const int N=1e5+5;
struct Node
{
	int v,w;
};
int in[N],out[N];
double dp[N];
int n,m,u,v,w,cnt=0;
queue<int> q;
vector<Node> G[N];
void bfs()
{
	q.push(n);//由于“倒过来想”,先加入n 
	//拓扑排序 
	while(!q.empty())
	{
		int u=q.front();
		q.pop();
		for(int i=0;i<G[u].size();i++)
		{
			int v=G[u][i].v,w=G[u][i].w;
			dp[v]+=(dp[u]+G[u][i].w)/out[v];//进行状态转移 
			in[v]--;
			if(!in[v]) q.push(v);
		}
	}
}
int main()
{
	cin>>n>>m;
	for(int i=1;i<=m;i++)
	{
		cin>>u>>v>>w;
		G[v].push_back(Node{u,w});//建反图 
		//统计出入度,也要反过来 
		in[u]++;
		out[u]++;
	}
	bfs();//拓扑排序 
	cout<<fixed<<setprecision(2)<<dp[1];
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值