绿豆蛙的归宿【期望】【DFS】

题目大意:

若一个点有k条出边,则走每条出边的概率均为1k。给出一个有向无环图,求从起点走到终点的所经过的路径总长度期望。
Input

4 4
1 2 1
1 3 2
2 3 3
3 4 4

Output

7.00

思路:

这很明显是一道数学期望的题目。但是由于之前没有做过这类的题目,所以做起来还是很吃力。
拿样例来说
这里写图片描述


1一开始肯定是有1.00的几率到达的,它有两条出边,分别到达点2和点3,那么,点2和点3就各有0.50的几率到达。
这里写图片描述
那么,点2又有一条出边到达点3,那么点3到达的几率就在原来的基础上又加上了点2的到达几率,所以点3的到达几率为1.00。
这里写图片描述
然后点3就只有一条出边,通向点4,所以点4到达几率就为1.00
这里写图片描述

每次当我们访问到一个点时,就讲答案sum加上它到达的概率×边权,即

sum+=s[x]num[x]×e[i].dis

且这个点的期望也要加上s[x]num[x]
然后继续向下搜索,搜到点n时就返回,然后将期望值减去s[x]num[x],防止重复计算。


代码:

#include <cstdio>
#include <iostream>
using namespace std;

int n,m,x,y,t;
double z,sum,s[300011],num[300011],head[300011],k;

struct edge  //邻接表
{
    int to,next;
    double dis;
}e[500011];

void add(int from,int to,double d)  //建边
{
    t++;
    e[t].dis=d;
    e[t].to=to;
    e[t].next=head[from];
    head[from]=t;
}

void dfs(int x)
{
    if (x==n) return;  //到达终点
    for (int i=head[x];i;i=e[i].next)
    {
        int v=e[i].to;
        double l=s[x]/num[x];  //计算路径长度期望
        s[v]+=l;  //加上期望
        sum+=e[i].dis*l;  //答案
        dfs(v);
        s[v]-=l;  //减掉期望
    }
}

int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=m;i++)
    {
        scanf("%d%d%lf",&x,&y,&z);
        add(x,y,z);  //建边
        num[x]++;
    }
    s[1]=1.00;  
    dfs(1);
    printf("%0.2lf\n",sum);
    return 0;
}
posted @ 2018-07-20 12:07  全OI最菜  阅读(88)  评论(0编辑  收藏  举报