zoukankan      html  css  js  c++  java
  • 洛谷4316 绿豆蛙的归宿(DAG递推/概率dp)

    题目大意:

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

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

    那么(displaystyleegin{aligned} Ans = sum_{e in E} f_ew_eend{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
    ", ans);
    	return 0;
    }
    

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

  • 相关阅读:
    MSsql bcp
    mssql 动态行转列。
    Ms sql 2000互转2005
    Ms sql pivot unpivot
    Ms sql将首字母大写
    java 进制相互转换
    Java 对字符反转操作。
    java jdbc 封装。。
    java SimpleDateFormat
    《more effective C++》条款10 防止构造函数里的资源泄露
  • 原文地址:https://www.cnblogs.com/oier/p/9596660.html
Copyright © 2011-2022 走看看