●Joyoi 绿豆蛙的归宿
题链:
http://www.joyoi.cn/problem/tyvj-1933
题解:
期望dp,拓扑序
定义dp[i]表示从i点到N点的期望距离。
令cnt[u]表示u的出度。
显然$$dp[u]=\sum_{u->v}(dp[v]+e(边权))* \frac{1}{cnt[u]}$$
由于是个DAG,所以拓扑排序后,从后向前dp即可。
题外话:为何不能正向dp:(希望聪明可爱的泥萌能看懂接下来的分析)
好吧,其实正向dp是可以的,但是没有反向dp来的直接和简单。
我们来看看弱弱的我当初觉得应该怎样去正向dp:
定义dp[i]表示从1点到i点的期望距离。
那么我们仿照之前反向dp的思路,我们找到当前v点的来源点u,
显然dp[v]肯定和dp[u]以及u的信息有关。
那u对v的贡献是不是就直接是$$dp[v]+=\frac{dp[u]+e(边权)}{cnt[u]}$$
即我们希望上式得到:
1到v的期望距离dp[v] = (1到u的期望距离 + u到v的边权)*(u到v的概率) [u为所有能到v的点]
为检验是否正确,我就试了几个小例子:
1.一个点没有边,答案为0,正确诶!(...)
2.两个点,一条边:1→ 2:3(箭头两头为边的起点和终点,3为边权),答案为3,又正确了!(废话)
3.三个点,3条边:1→ 2:1,1→ 3:3,2→ 3:2,用脚趾头也算得出来答案为3,可是程序喜闻乐见地输出了一个4。
???怎么回事,dp哪里出现的问题?
经过一番分析,我找到了问题的根源,就处在dp转移时加的边权e那里。
在详细说明问题之前,我们先来看看通常倒着做的期望dp里面的各个状态的期望是如何实现递推的,
即一个状态j的期望是如何通过计算的到其前继状态i的期望的。
假设状态i转移到状态j的概率为p,代价为w,
用E(j)表示从状态j到结束的期望,E(i)表示从状态i到结束的期望,E(i→ j)表示状态i下一步必须为状态j,再到结束的期望。
由期望的定义可以知道:
E(j)=p1*w1+p2*w2+p3*w3+...+pn*wn(即第一种情况的概率*权值+第二种情况的概率*权值+...)
然后如果钦定i状态必须转移到j的话(代价为w),不那发现,
E(i→ j)=p1*(w1+w)+p2*(w2+w)+p3*(w3+w)+...+pn*(wn+w)
注意到了么,从i→ j这个状态到结束的情况数没有变化,每种情况的概率也没变,唯一的变化只是每种情况的权值都加了w。
而通常倒着做的dp,我们定义的状态往往是表示从该状态出发到结束的期望,即把该状态看成了子问题的起点。
所以E(j)中所有的概率之和p1+p2+p3+...+pn = 1
那么:E(i→ j)=p1*(w1+w)+p2*(w2+w)+p3*(w3+w)+...+pn*(wn+w)
=p1*w1+p2*w2+p3*w3+...+pn*wn + p1*w+p2*w+p3*w+..+pn*w
=E(j)+w
然后再把这个所谓的"钦定"改为"有p的概率从状态i到状态j",并累加进E(i):
E(i)+=p*E(i→ j)即E(i)+=p*(E(j)+w)
本题我们反向dp的转移就是这么推出来的。
那么回到之前的问题,为何那样正向dp就出错了:
同样地,我们设当前在i点,其前继状态为j点,从j转移到i有p的概率,代价为w,
用E(j)表示从起点到j点的期望距离,E(i)表示从起点到i点的期望距离,E(j→ i)表示i点由j点而来的情况下,从起点到i点的期望距离。
我们用期望定义来写出E(j)的构成:
E(j)=p1*w1+p2*w2+p2*w3+...+pn*wn
然后类似上面的步骤,我们钦定i状态必须由j状态转移而来:
E(j→ i)=p1*(w1+w)+p2*(w2+w)+p3*(w3+w)+...+pn*(wn+w)
当然这里还没有任何问题,同样的是情况数没有变化,每种情况的概率也没变,唯一的变化只是每种情况的权值都加了w。
我们继续,尝试化简E(j→ i):
E(j→ i)=p1*(w1+w)+p2*(w2+w)+p3*(w3+w)+...+pn*(wn+w)
=p1*w1+p2*w2+p3*w3+...+pn*wn + p1*w+p2*w+p3*w+..+pn*w
=E(j)+p1*w+p2*w+p3*w+..+pn*w
然后上式等于E(j)+w么?
问题就出在这里。
当然不,因为这个dp定义下,每个dp状态的起点都是1号点,也就是说,
E(j)里面每种情况的概率应该是:第一种从1点到j的情况的概率p1,第二种从1点到j点的情况的概率p2,第三种p3...pn
但是显然1点不会只到j点,(好吧除了之前搞笑用的第一组和第二组测试数据)
所以g(j) = p1+p2+p3+...+pn ≠ 1,
那么顺理成章地可以得到 E(j→ i) ≠ E(j) + w
也就可以得到,没有所谓的"钦定"而是换成概率p,E(i)也不能加上p*(E(j)+w),
所以正向dp错就错在$dp[v]+=\frac{dp[u]+e(边权)}{cnt[u]}$加的那个"dp[u]+e",
至于我之前说的正向dp也可以正确,泥萌应该也有点思路了吧:
因为构成来源状态的期望值的那些概率的和g(j)不等于1,所以不能直接加上权值w,
那么我们就在dp的同时维护出从起点到每个状态的概率g,
然后再看上面的E(j→ i) = E(j)+p1*w+p2*w+p3*w+..+pn*w = E(j) + g(j)*w
也就是说dp本题正向dp的转移写成$dp[v]+=\frac{dp[u]+g[u]*e(边权)}{cnt[u]}$就完成没问题啦。
(实测AC,代码在下面的注释部分)
啰啰嗦嗦地说了1mol,希望对泥萌在理解正向和反向进行期望dp方面能有所帮助。
代码:
#include<bits/stdc++.h>
#define MAXN 100005
using namespace std;
struct Edge{
int ent;
int to[MAXN*2],val[MAXN*2],nxt[MAXN*2],head[MAXN];
Edge():ent(2){}
void Adde(int u,int v,int w){
to[ent]=v; val[ent]=w;
nxt[ent]=head[u]; head[u]=ent++;
}
}E,F;
double dp[MAXN];
int order[MAXN],in[MAXN],cnt[MAXN];
int N,M,ont;
void bfs(){
static queue<int>Q;
Q.push(1);
while(!Q.empty()){
int u=Q.front(); Q.pop();
order[++ont]=u;
for(int e=E.head[u];e;e=E.nxt[e]){
int v=E.to[e];
in[v]--; if(!in[v]) Q.push(v);
}
}
}
int main(){
ios::sync_with_stdio(0);
cin>>N>>M;
for(int i=1,u,v,w;i<=M;i++)
cin>>u>>v>>w,E.Adde(u,v,w),in[v]++,cnt[u]++,F.Adde(v,u,w);
bfs();
for(int i=N-1;i>=1;i--){
int u=order[i];
for(int e=E.head[u];e;e=E.nxt[e]){
int v=E.to[e];
dp[u]+=(dp[v]+E.val[e])/cnt[u];
}
}
cout<<fixed<<setprecision(2)<<dp[1]<<endl; /*正推
static double g[MAXN]; g[1]=1;
for(int i=2;i<=N;i++){
int u=order[i];
for(int e=F.head[u];e;e=F.nxt[e]){
int v=F.to[e];
dp[u]+=(dp[v]+g[v]*F.val[e])/cnt[v];
g[u]+=g[v]/cnt[v];
}
}
cout<<fixed<<setprecision(2)<<dp[N]<<endl;
*/
return 0;
}
●Joyoi 绿豆蛙的归宿的更多相关文章
- 【BZOJ3036】绿豆蛙的归宿 拓补排序+概率
[BZOJ3036]绿豆蛙的归宿 Description 随着新版百度空间的下线,Blog宠物绿豆蛙完成了它的使命,去寻找它新的归宿. 给出一个有向无环的连通图,起点为1终点为N,每条边都有一个长度. ...
- BZOJ3036: 绿豆蛙的归宿&Wikioi2488:绿豆蛙的归宿
3036: 绿豆蛙的归宿 Time Limit: 2 Sec Memory Limit: 128 MBSubmit: 108 Solved: 73[Submit][Status] Descript ...
- BZOJ 3036: 绿豆蛙的归宿( 期望dp )
从终点往起点倒推 . 在一个图 考虑点 u , 出度为 s : s = 0 , d[ u ] = 0 ; s ≠ 0 , 则 d( u ) = ( ∑ d( v ) ) / s ( ( u , v ) ...
- BZOJ3036绿豆蛙的归宿
BZOJ3036绿豆蛙的归宿 锲下陟凝 褰宓万 郝瓦痕膳 叶诙摞 А知π剧 椐猊∫距 屠缲佗 ゲ蕖揪 俜欧彖鹤 磲砩ほ #琛扶 觅电闸ス 捆鳢げ 浜窠 魂睨"烁 蕞滗浼 洒ヂ跪 ...
- [COGS 1065] 绿豆蛙的归宿
先贴题面w 1065. [Nescafe19] 绿豆蛙的归宿 ★ 输入文件:ldfrog.in 输出文件:ldfrog.out 简单对比时间限制:1 s 内存限制:128 MB 随着新 ...
- P4316 绿豆蛙的归宿(期望)
P4316 绿豆蛙的归宿 因为非要用bfs所以稍微麻烦一点qwq(大家用的都是dfs) 其实问题让我们求的就是经过每条边的概率*边权之和 我们可以用bfs把图遍历一遍处理概率,顺便把每条边的概率*边权 ...
- 【BZOJ 3036】 3036: 绿豆蛙的归宿 (概率DP)
3036: 绿豆蛙的归宿 Time Limit: 2 Sec Memory Limit: 128 MBSubmit: 491 Solved: 354 Description 随着新版百度空间的下线 ...
- [cogs1065]绿豆蛙的归宿
1065. [Nescafe19] 绿豆蛙的归宿 [题目描述] 给出一个有向无环的连通图,起点为1终点为N,每条边都有一个长度.绿豆蛙从起点出发,走向终点.到达每一个顶点时,如果有K条离开该点的道路, ...
- codevs 2488 绿豆蛙的归宿
2488 绿豆蛙的归宿 http://codevs.cn/problem/2488/ 时间限制: 1 s 空间限制: 64000 KB 题目等级 : 黄金 Gold 题目描述 Descrip ...
随机推荐
- 听翁恺老师mooc笔记(12)--结构中的结构
结构数组: 和C语言中的int,double一样,一旦我们做出一个结构类型,就可以定义这个结构类型的变量,也可以定义这个结构类型的数组.比如下面这个例子: struct date dates[100] ...
- 凡事预则立-于Beta冲刺前
凡事预则立,在Beta开始前的描述 在Beta项目冲刺开始之前,我们小组组织了一次活动室的讨论,明确了一下分工和即将来临的Beta冲刺要处理的问题和需要继续改进的地方.顺带补上一直没有的照片: 针对几 ...
- Mybash的实现
Mybash的实现 要求: 使用fork,exec,wait实现mybash 写出伪代码,产品代码和测试代码 发表知识理解,实现过程和问题解决的博客(包含代码托管链接) 背景知识 1. fork 使用 ...
- 单向链表在O(1)时间内删除一个节点
说删链表节点,第一时间想到就是遍历整个链表,找到删除节点的前驱,改变节点指向,删除节点,但是,这样删除单链表的某一节点,时间复杂度就是O(n),不符合要求: 时间复杂度是O(n)的做法就不说了,看看O ...
- New UWP Community Toolkit - RangeSelector
概述 前面 New UWP Community Toolkit 文章中,我们对 V2.2.0 版本的重要更新做了简单回顾,其中简单介绍了 RangeSelector,本篇我们结合代码详细讲解一下 Ra ...
- Linux知识积累(6) 系统目录及其用途
linux系统常见的重要目录以及各个目作用:/ 根目录.包含了几乎所有的文件目录.相当于中央系统.进入的最简单方法是:cd /./boot引导程序,内核等存放的目录.这个目录,包括了在引导过程中所必需 ...
- 新概念英语(1-43)Hurry up!
新概念英语(1-43)Hurry up! How do you know Sam doesn't make the tea very often? A:Can you make the tea, Sa ...
- Jetty入门(1-2)eclipse集成jetty插件并发布运行应用
一.eclipse集成jetty插件 1.从市场安装jetty插件 2.使用jetty插件发布应用和配置运行环境 debug配置默认共用上述run配置 3.使用jetty插件启动运行和停止运行选中的应 ...
- 基于python的统计公报关键数据爬取 update
由于之前存在的难以辨别市本级,全市相关数据的原因,经过考虑采用 把含有关键词的字段全部提取进行人工辨别的方法 在其余部分不改变的情况下,更改test部分 def test(real_Title,rea ...
- webservice面试题
webservice是什么? 1.基于WEB的服务,服务端整出一些资源让客户端应用访问(提供数据) 2.webservice是一个跨语言跨平台的规范(抽象) 3.是多个跨语言跨平台的应用间通信整合的方 ...