BZOJ 3036 浅谈逆拓扑序递推期望转移方程

来源:互联网 发布:eclipse json编辑器 编辑:程序博客网 时间:2024/06/05 07:23

这里写图片描述
世界真的很大
期望这个东西逐渐地也没有那么玄学了
期望的线性性决定了其可以通过递推来得到状态转移方程
有向无环图的话一定要想到拓扑序
只要有向就行不一定非要用题目给出的方向,思路还是要灵活

看题先:

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*/

嗯,就是这样

阅读全文
0 0
原创粉丝点击