世界真的很大
期望这个东西逐渐地也没有那么玄学了
期望的线性性决定了其可以通过递推来得到状态转移方程
有向无环图的话一定要想到拓扑序
只要有向就行不一定非要用题目给出的方向,思路还是要灵活
看题先:
description
随着新版百度空间的下线,Blog宠物绿豆蛙完成了它的使命,去寻找它新的归宿。
给出一个有向无环的连通图,起点为1终点为N,每条边都有一个长度。绿豆蛙从起点出发,走向终点。
到达每一个顶点时,如果有K条离开该点的道路,绿豆蛙可以选择任意一条道路离开该点,并且走向每条路的概率为 1/K 。
现在绿豆蛙想知道,从起点走到终点的所经过的路径总长度期望是多少?
input
第一行: 两个整数 N M,代表图中有N个点、M条边
第二行到第 1+M 行: 每行3个整数 a b c,代表从a到b有一条长度为c的有向边
output
从起点到终点路径总长度的期望值,四舍五入保留两位小数。
求走到终点的路径期望值
先考虑在每个点,青蛙都是随机走的,对于每个点,他走每一条出边的概率都相同
这一点在提示我们可以采用期望逐步转移的方式来得到答案
因为转移期望的必须条件之一,每一部之间的概率,我们都可以得到,就是1 / 点的度数
考虑逐步转移,由于期望具有线性性,决定了一个状态的期望可以由后继状态的期望乘以概率累加得到
令fi表示走到i点的期望步数
题目性质决定了已经到过的点不可能走回来,所以不用考虑到几次的问题
那么很显然fi= sigma (fj + w(i,j))/i的度数
因为期望线性性,所以可以由后继状态的期望值得到
考虑一个点的答案是由后继点的答案得到的,而且我们要的是第一个点的答案,而n号点的期望值肯定是0
很显然我们应该从后往前推导
所以边干脆就建成反边
为了在一张图里面倒推,而且还是DAG,很容易想到拓扑序
就倒着用拓扑序逆推就好了
完整代码:
#include<stdio.h>
#include<algorithm>
#include<queue>
using namespace std;
struct edge
{
int u,v,w,last;
}ed[500010];
queue <int> state;
int n,m,num=0,in[200010],du[200010],head[200010];
double f[200010];
void add(int u,int v,int w)
{
num++;
ed[num].v=v;
ed[num].w=w;
ed[num].last=head[u];
head[u]=num;
}
void TOP()
{
state.push(n);
f[n]=0;
while(!state.empty())
{
int u=state.front();
state.pop();
for(int i=head[u];i;i=ed[i].last)
{
int v=ed[i].v;
in[v]--,f[v]+=(double) (ed[i].w+f[u])/du[v];
if(!in[v])
state.push(v);
}
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(v,u,w);
in[u]++,du[u]++;
}
TOP();
printf("%0.2lf\n",f[1]);
return 0;
}
/*
EL PSY CONGROO
*/
嗯,就是这样