zoukankan      html  css  js  c++  java
  • $Luogu$ $P4316$ 绿豆蛙的归宿(附期望 $dp$ 的设计总结)

    链接

    背景

    李煜东, (Nescafé) (19)(NOIP) 模拟赛 (T1)(Luogu) (P4316/TYVJ1933)

    题意

    给定一张 (n) 个点 (m) 条边的有边权的 (DAG) (有向无环图),起点为 (1) ,终点为 (n) 。从起点出发,每个点连接的所有点等概率地前往,求到达终点期望的总路径长度。答案保留 (2) 位小数。

    解法

    显然最终的状态只有一个,就是到达了 (n) 点。因此考虑逆推。
    不妨考虑设 (f_x) 表示 (x) 点到终点路径的期望长度, (dis_{x,y}) 表示 (x) 点到 (y) 点的边长(要求 (x,y) 是同一条边的两端)。
    根据期望的定义和性质,则转移有: (f_x=frac{ sum { f_y+dis_{x,y} } }{k}) (要求 (x,y) 是同一条边的两端, (k) 是所有符合条件的 (y) 点数量)。
    易发现所有符合条件的 (y) 点数量就是 (x) 点的出度。预处理每个点 (x) 的出度 (deg_x) ,则 (f_x=frac{ sum { f_y+dis_{x,y} } }{deg_x}) (要求 (x,y) 是同一条边的两端)。拓扑排序时更新 (f) 即可。

    (trick)

    期望 (dp) 的设计:

    (1.) 状态与一般 (dp) 无异,求什么设什么。

    (2.) 转移方法有两种(都是递推):顺推和逆推。以已知状态多的或者总状态少的一端开始推。

    (3.) 转移的实现方式有填表法(从上一个状态转移而来)和刷表法(从下一个状态转移而来)两种。

    设状态的例子:求 (n) 个人做某事的期望次数。显然要设 (f_i) 表示第 (i) 个人做完后的期望次数。

    刷表法的例子:设 (f_i) 表示还要走 (i) 步到达终点的期望次数。转移模型为 (f_i= sum_limits{i ightarrow j} p_{i ightarrow j} imes f_j+w_{i ightarrow j}) ,其中 (p) 表示转移过程的概率, (w) 表示转移过程的权值或者对答案的贡献。

    细节

    (1.) 为了逆推需要建反图(对所有边取反)。

    (2.) 具体更新时由于边是反向的,转移方程里的 (x,y) 要交换位置。

    (3.) 拓扑排序的细节不要错。只把入度为 (0) 的点推进队列。

    代码

    $View$ $Code$
    
    //省略头文件
    using namespace std;
    inline int read()
    {
    	int ret=0,f=1;
    	char ch=getchar();
    	while(ch>'9'||ch<'0')
    	{
    		if(ch=='-')
    			f=-1;
    		ch=getchar();
    	}
    	while(ch>='0'&&ch<='9')
    	{
    		ret=(ret<<1)+(ret<<3)+ch-'0';
    		ch=getchar();
    	}
    	return ret*f;
    }
    int n,m,u,v,w;
    int num,head[200005],ind[100005],deg[100005];
    double f[100005];
    bool vis[100005];
    queue q;
    struct edge
    {
    	int ver,nxt,w;
    }e[200005];
    inline void adde(int u,int v,int w)
    {
    	e[++num].ver=v;
    	e[num].nxt=head[u];
    	e[num].w=w;
    	head[u]=num;
    }
    inline void topsort()
    {
    	q.push(n);
    	while(!q.empty())
    	{
    		int x=q.front();
    		q.pop();
    		for(register int i=head[x];i;i=e[i].nxt)
    		{
    			int y=e[i].ver;
    			ind[y]--;
    			if(!ind[y])
    				q.push(y);
    			f[y]+=(f[x]+e[i].w)/deg[y];
    		}
    	}
    }
    int main()
    {
    	n=read();
    	m=read();
    	for(register int i=1;i<=m;i++)
    	{
    		u=read();
    		v=read();
    		w=read();
    		adde(v,u,w);
    		ind[u]++;
    		deg[u]++;
    	}
    	topsort();
    	printf("%0.2lf
    ",f[1]);
    	return 0;
    }
    
  • 相关阅读:
    【k8s学习笔记】Kubernetes API概念
    【k8s学习笔记】使用 kubeadm 部署 v1.18.5 版本 Kubernetes集群
    通过yum展示安装包依赖关系,下载rpm包
    【kubeadm初始化报错】failed to run Kubelet: misconfiguration: kubelet cgroup driver: "cgroupfs" is different from docker cgroup driver: "systemd"
    npm 安装依赖报错解决:npm ERR! Unexpected end of JSON input while parsing near
    【K8s学习笔记】K8s是如何部署应用的?
    【K8S学习笔记】初识K8S 及架构组件
    python包的多种安装方式(内网)
    Python利用ConfigParser读取配置文件
    Tomcat 容器模型
  • 原文地址:https://www.cnblogs.com/Peter0701/p/11735314.html
Copyright © 2011-2022 走看看