题目链接:迷失游乐园

  这道题也没有传说中的那么难写吗→_→

  似乎有篇博客讲得特详细……附上链接:戳这里

  如果这道题不是基环树,而就是一棵树的话,我们来考虑改怎么做。因为树上的路径只有向上、向下两种走法,于是我们可以记\(down_u\)表示从\(u\)往下走的期望长度,\(up_u\)表示从\(u\)往上走的期望长度,这就很好转移了。

  显然对于一个点\(u\),设它的父亲为\(fa_u\),有\(son_u\)个孩子和\(num_u\)个父亲(根节点认为没有父亲),那么显然有:

\[down_u=\frac{\sum_{fa_v=u}down_v+dis(u,v)}{son_u}\]

  这就是往各个孩子走的概率相等,于是求个平均值就可以了。

  然后我们接着考虑\(up_u\)怎么求:

\[up_u=dis(fa_u,u)+\frac{up_{fa_u}\times num_u+down_{fa_u}\times son_{fa_u}-down_u-dis(fa_u,u)}{son_{fa_u}-1+num_{fa_u}}\]

  因为我们下一步从\(u\)走到了\(fa_u\),那么之后一步可以往下也可以向上。往上走的总和就是\(up_{fa_u}\times num_u\),往下走的话由于不能走回头路,于是就用\(down_{fa_u}\times son_{fa_u}\)减去从\(u\)往下的\(down_u\)和从\(fa_u\)走过来的\(dis(fa_u,u)\)即可。由于期望相当于平均值,共有\(son_{fa_u}-1+num_{fa_u}\)种种情况,总和除以总情况数就是期望。

  于是树的情况就做完辣!接下来让我们来考虑基环树的情况。

  我们可以把基环树看成一个环上面长着许多棵大大小小的树。在这种情况下,我们发现每棵树的根节点也可以往上走了,并且在环上有两种走法。为了方便接下来的计算,我们可以先把环上每个点的\(down\)值给求出来。我们可以对于每个点,枚举它顺时针走到哪个点,那么在这个点往它的子树走的概率我们是可以递推算出来的,并且由于我们知道了每个点的\(down\)值,所以知道会向下走多远,于是就可以算出顺时针走的期望了。逆时针同理。于是我们就在\(O(环长^2)\)的时间内求出环上每个点的\(up\)值了。剩下的部分就是树的情况了,只不过对于每个环上的点\(x\)有\(num_x=2\),因为有往上有两种走法。

  说了这么多,最后的答案就是:\[\sum_{i=1}^{n}\frac{up_i\times num_i+down_i\times son_i}{num_i+son_i}\]

  代码也不长:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
#define maxn 100010 using namespace std;
typedef double llg; int n,m,du[maxn],dis[maxn],hf[maxn];//hf[u]表示u有几个父亲,环上的点认为有两个父亲
int dfn[maxn],a[maxn],la,b[maxn],fa[maxn];//a数组中存的是环上的点,b[i]存的是a[i]与a[i-1]之间的距离
int head[maxn],next[maxn<<1],to[maxn<<1],c[maxn<<1],tt;
llg dn[maxn],up[maxn],ans;//dn就是向下走的期望长度,up就是向上走的期望长度
bool vis[maxn]; int getint(){
int w=0;bool q=0;
char c=getchar();
while((c>'9'||c<'0')&&c!='-') c=getchar();
if(c=='-') c=getchar(),q=1;
while(c>='0'&&c<='9') w=w*10+c-'0',c=getchar();
return q?-w:w;
} void link(int x,int y){
to[++tt]=y;next[tt]=head[x];head[x]=tt;
to[++tt]=x;next[tt]=head[y];head[y]=tt;
c[tt-1]=c[tt]=getint();
} void down(int u){//求向下的期望值
int cnt=0; vis[u]=1;
for(int i=head[u],v;v=to[i],i;i=next[i])
if(!vis[v]) dis[v]=c[i],down(v),cnt++,dn[u]+=dn[v]+c[i];
if(cnt) dn[u]/=cnt; du[u]=cnt; vis[u]=0;
} void dfs(int u,int fa){//求向上的期望值
vis[u]=1; if(fa) hf[u]=1;
if(fa>0) up[u]+=(up[fa]*hf[fa]+du[fa]*dn[fa]-dn[u]-dis[u])/(du[fa]-1+hf[fa]);
for(int i=head[u],v;v=to[i],i;i=next[i])
if(!vis[v]) up[v]+=c[i],dfs(v,u);
} void getrt(int rt,int x){//抠环
for(int u=x;u!=fa[rt];u=fa[u])//dis[u]表示u向它的父亲走的距离
a[++la]=u,b[la+1]=dis[u],vis[u]=1,hf[u]=2;
} void Tarjan(int u,int ff){//抠环
dfn[u]=++tt; fa[u]=ff;
for(int i=head[u],v;v=to[i],i;i=next[i])
if(!dfn[v]) dis[v]=c[i],Tarjan(v,u);
else if(dfn[v]>dfn[u]) b[1]=c[i],getrt(u,v);
} void solve(int u,int j,int z){//在环上走
llg now=0.5,di=0;//di即为在环上走过的距离,now为当前的概率
for(int i=1;i<la;i++){
if(z==-1) di+=b[j]; j+=z;
if(j==la+1) j=1; if(j==0) j=la;
if(z==1) di+=b[j];
if(i==la-1){up[u]+=now*(di+dn[a[j]]);}
else up[u]+=now*du[a[j]]*(dn[a[j]]+di)/(du[a[j]]+1);
now/=(du[a[j]]+1);
}
} void work(){//特殊处理环
tt=0; Tarjan(1,0);
for(int i=1;i<=la;i++) down(a[i]),vis[a[i]]=1;//先求出环上每个点向下的期望
for(int i=1,u;u=a[i],i<=la;i++) solve(u,i,1),solve(u,i,-1);//正反两种走法在环上走
for(int i=1;i<=la;i++) dfs(a[i],0);//子树内求解向上走的期望值
} int main(){
File("park");
n=getint(); m=getint();
for(int i=1;i<=m;i++) link(getint(),getint());
if(m==n-1) down(1),dfs(1,0);
else work();
for(int i=1;i<=n;i++)
ans+=(up[i]*hf[i]+dn[i]*du[i])/(du[i]+hf[i]);
printf("%.5lf",ans/n);
return 0;
}

BZOJ 2878 【NOI2012】 迷失游乐园的更多相关文章

  1. BZOJ 2878: [Noi2012]迷失游乐园( 树形dp )

    一棵树的话直接树形dp(求出往下走和往上走的期望长度). 假如是环套树, 环上的每棵树自己做一遍树形dp, 然后暴力枚举(环上的点<=20)环上每个点跑经过环上的路径就OK了. -------- ...

  2. bzoj 2878 [Noi2012]迷失游乐园——树上的期望dp

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2878 很好的树上概率题的思路,就是分成up和down. 代码中有众多小细节.让我弃疗好几天的 ...

  3. bzoj 2878: [Noi2012]迷失游乐园

    #include<iostream> #include<cstring> #include<cstdio> #define M 100005 #define ld ...

  4. bzoj 2878: [Noi2012]迷失游乐园【树上期望dp+基环树】

    参考:https://blog.csdn.net/shiyukun1998/article/details/44684947 先看对于树的情况 设d[u]为点u向儿子走的期望长度和,du[u]为u点的 ...

  5. 【BZOJ 2878】 2878: [Noi2012]迷失游乐园 (环套树、树形概率DP)

    2878: [Noi2012]迷失游乐园 Description 放假了,小Z觉得呆在家里特别无聊,于是决定一个人去游乐园玩.进入游乐园后,小Z看了看游乐园的地图,发现可以将游乐园抽象成有n个景点.m ...

  6. 2878: [Noi2012]迷失游乐园 - BZOJ

    Description 放假了,小Z觉得呆在家里特别无聊,于是决定一个人去游乐园玩.进入游乐园后,小Z看了看游乐园的地图,发现可以将游乐园抽象成有n个景点.m条道路的无向连通图,且该图中至多有一个环( ...

  7. BZOJ 2878([Noi2012]-失落的游乐园树DP+出站年轮加+后市展望DP+vector的erase)

    2878: [Noi2012]迷失乐园 Time Limit: 10 Sec  Memory Limit: 512 MBSec  Special Judge Submit: 319  Solved:  ...

  8. [bzoj2878][Noi2012]迷失游乐园(基环树dp)

    [bzoj2878][Noi2012]迷失游乐园(基环树dp) bzoj luogu 题意:一颗数或是基环树,随机从某个点开始一直走,不走已经到过的点,求无路可走时的路径长期望. 对于一棵树: 用两个 ...

  9. 【BZOJ 2878】 [Noi2012]迷失游乐园

    Description 放假了,小Z觉得呆在家里特别无聊,于是决定一个人去游乐园玩.进入游乐园后,小Z看了看游乐园的地图,发现可以将游乐园抽象成有n个景点.m条道路的无向连通图,且该图中至多有一个环( ...

  10. NOI2012 : 迷失游乐园

    终于补完NOI2012了好开心~ 题目大意:给定一棵树或者环套外向树,求出从中随机选一条简单路径的期望长度,环上点数不超过20. 设 d[x]表示x的度数,ch[x]表示x孩子个数 up[x]表示x向 ...

随机推荐

  1. [leetcode]从中序与后序/前序遍历序列构造二叉树

    从中序与后序遍历序列构造二叉树 根据一棵树的中序遍历与后序遍历构造二叉树. 注意: 你可以假设树中没有重复的元素. 例如,给出 中序遍历 inorder = [9,3,15,20,7] 后序遍历 po ...

  2. Windows10子系统安装ubuntu+kali渗透环境

    Windows10安装子系统ubuntu,安装完ubuntu后再安装katoolin才能使用kali. (katoolin渗透测试的Linux发行版,它可以让你在其他Linux发行版上使用Kali的全 ...

  3. java内存结构JVM——java内存模型JMM——java对象模型JOM

    JVM内存结构 Java代码是要运行在虚拟机上的,而虚拟机在执行Java程序的过程中会把所管理的内存划分为若干个不同的数据区域,这些区域都有各自的用途.其中有些区域随着虚拟机进程的启动而存在,而有些区 ...

  4. 冲刺One之站立会议7 /2015-5-20

    2015-5-20 在登陆成功之后要实现的是聊天界面的交互过程,不同的IP进行信息和数据的传递,这方面我们上学期Java实验里面有过相关的内容,我们把它拿过来改了一下格式,试着看能不能成功,目前还没实 ...

  5. vs2013 CodeLens

    那东西叫 CodeLens  只有VS2013 旗舰版 (update 2及以上) 才可以用,高级版 专业版都没有.如何打开CodeLens呢?在VS菜单栏 >> 工具 >> ...

  6. 新的Calculator的规范作业

    附加作业题目 第三次作业 mygithub:sonnypp 这是开学来第一次写随笔,这一次的作业是对上一次作业的修改,对于上一次作业,在学长老师的帮助下,我重新修改了下代码,将.h文件分成了一个Sca ...

  7. “吃神么,买神么”的第三个Sprint冲刺总结

    第三阶段Spring的目标以及完成情况: 时间:6.16——6.26(10天) 目标:第三阶段主要是前台设计的修改完善,以及数据库成功连接,完成小部分功能 情况:前台界面完善,完成小部分功能(发布功能 ...

  8. APP案例分析——Steam

    本次作业的分析对象是Steam,一款全球最大最广泛的游戏平台.之所以选择Steam是因为我已经在这上面挥洒了大量的青春,对它也有了很深的感情. 调研.评测 个人第一次上手体验 打开首页就可以看到琳琅满 ...

  9. Java通用oracle和mysql数据库连接

    Java中oracle数据库连接写一个通用类UBUtil(){} import java.io.InputStream; import java.sql.*; import java.util.Pro ...

  10. web_custom_request和web_submit_data

    网络上很多说明这2个函数区别的文章,我就从其他摘抄了内容,其中区别自己查看附录,我主要说明2点 (1)用web_custom_request提交请求如果是json,则会会使用关键字符{},但是{},是 ...