洛谷4316 绿豆蛙的归宿(DAG递推/概率dp)

题目大意:

给定一个DAG,求起点到终点的路径长度期望

根据题意可以知道每一条边都有一定概率被走到

那么\(\displaystyle\begin{aligned} Ans = \sum_{e \in E} f_ew_e\end{aligned}\),其中\(E\)是边的集合,\(f_e\)是经过边\(e\)的期望次数,\(w_e\)是边\(e\)的边权

这样我们只需要求经过每一条边的期望次数

对于每一条边,经过这条边的期望次数就是经过这条边起点的期望次数除以这条边起点的出度

这样我们就只需要求经过每一个点的期望次数

由于是DAG,我们在DAG上拓扑排序递推一下即可

在地推的过程中,我们可以顺便求出经过每条边的期望次数

(其实经过某一个点的期望次数就等于它所有入边的期望次数的和,它所有出边的期望次数就等于它的期望次数除以它的出度)

详见代码

#include <cstdio>
#include <iostream>

using namespace std;

struct edge
{
    int v, w, ne;
}a[200010];

int n, m, tmp, top;
int in[100010], out[100010], h[100010], s[100010];
double f[200010], p[100010], ans;

int main()
{
    scanf("%d%d", &n, &m);
    for (int x, y, z, i = 1; i <= m; i++)
    {
        scanf("%d%d%d", &x, &y, &z);
        a[++tmp] = (edge){y, z, h[x]};
        h[x] = tmp;
        out[x]++;
        in[y]++;
    }
    s[++top] = 1;
    p[1] = 1;
    while (top > 0)//用一个栈维护所有可以选择的点
    {
        int x = s[top--];
        for (int i = h[x]; i != 0; i = a[i].ne)
        {
            in[a[i].v]--;
            p[a[i].v] += p[x] / out[x];//累加经过一个点的期望次数
            f[i] = p[x] / out[x];//计算经过一个边的期望次数
            if (in[a[i].v] == 0)
                s[++top] = a[i].v;
        }
    }
    for (int i = 1; i <= m; i++)
        ans += f[i] * a[i].w;
    printf("%.2f\n", ans);
    return 0;
}

拓展:如果不是DAG,可以列方程组求解,详见[HNOI2013]游走

转载于:https://www.cnblogs.com/oier/p/9596660.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值