题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2878

这个博客写得很好:https://www.cnblogs.com/qt666/p/7252284.html

其实就是分成子树部分(down)和向上的部分(up)来考虑、转移;

要想清楚vis的作用等等,还有那个ed的使用,是和fa配套的,也就是只在子树中使用;

期望就是其他状态的期望和除以总状态数,只要想清楚有些什么状态就很好转移了!

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int const maxn=3e5+;
int n,m,fa[maxn],f[maxn],son[maxn],head[maxn],ct,ed[maxn],cir[maxn],cnt,dfn[maxn],tim,b[maxn];
double down[maxn],up[maxn],ans;
bool vis[maxn];
struct N{
int to,next,w;
N(int t=,int n=,int w=):to(t),next(n),w(w) {}
}edge[maxn];
void add(int x,int y,int z)
{
edge[++ct]=N(y,head[x],z);head[x]=ct;
edge[++ct]=N(x,head[y],z);head[y]=ct;
}
void dfs_down(int x)
{
vis[x]=;int tot=;
for(int i=head[x],v;i;i=edge[i].next)
{
if(vis[v=edge[i].to])continue;
ed[v]=edge[i].w;//
dfs_down(v);tot++;
down[x]+=down[v]+edge[i].w;
}
if(tot)down[x]/=tot;//
son[x]=tot;vis[x]=;//
}
void dfs_up(int x,int u)
{
// fa[x]=u;f[x]=1;
// if(u&&son[u])up[x]+=(up[u]+down[u]*son[u]-down[x]-ed[x])/son[u]+ed[x];
// for(int i=head[x],v;i;i=edge[i].next)
// if(!f[v=edge[i].to])ed[v]=edge[i].w,dfs_up(v,x);
vis[x]=;if(u) f[x]=;
if((son[u]-+f[u])&&u) up[x]+=(up[u]*f[u]+son[u]*down[u]-down[x]-ed[x])/(son[u]-+f[u]);//特判根节点(只有一个son的)
for(int i=head[x],v;i;i=edge[i].next)
if(!vis[v=edge[i].to]) /*ed[i]=edge[i].w,*/
up[v]+=edge[i].w,dfs_up(v,x);//在down时已求出ed
}
void make(int rt,int x)
{
for(int i=x;i!=fa[rt];i=fa[i])//不是i!=rt !!!
cir[++cnt]=i,b[cnt+]=ed[i],f[i]=,vis[i]=;//vis在dfs_down中会用
//犯蠢把 cir[++cnt]=i 写成 cir[++cnt]=x ,调了半天!!!
}
void tarjan(int x,int ff)
{
dfn[x]=++tim;fa[x]=ff;
for(int i=head[x],v;i;i=edge[i].next)
{
if(!dfn[v=edge[i].to])ed[v]=edge[i].w,tarjan(v,x);
else if(dfn[v]>dfn[x])b[]=edge[i].w,make(x,v);
}
}
void solve(int x,int j,int step)
{
double g=0.5,d=;
for(int i=;i<cnt;i++)//所求的都是up[x]!
{
if(step==-)d+=b[j];j+=step;//是b而不是ed
if(j==)j=cnt;if(j==cnt+)j=;
if(step==)d+=b[j];//j+后再+b[j],顺、逆时针有所区分
if(i==cnt-)up[x]+=g*(d+down[cir[j]]);
else up[x]+=g*(d+down[cir[j]])*son[cir[j]]/(son[cir[j]]+);
g/=son[cir[j]]+;
}
}
void work()//!
{
tarjan(,);
for(int i=;i<=cnt;i++)dfs_down(cir[i]),vis[cir[i]]=;//
for(int i=;i<=cnt;i++)solve(cir[i],i,),solve(cir[i],i,-);
for(int i=;i<=cnt;i++)dfs_up(cir[i],);//由于vis,只处理子树
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=,x,y,z;i<=m;i++)
scanf("%d%d%d",&x,&y,&z),add(x,y,z);
if(m==n-)dfs_down(),dfs_up(,);
else work();
for(int i=;i<=n;i++)
ans+=(down[i]*son[i]+up[i]*f[i])/(son[i]+f[i]);
printf("%.5lf",ans/n);//ans/n!
return ;
}

bzoj2878 [Noi2012]迷失游乐园——概率期望DP的更多相关文章

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

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

  2. BZOJ2878 NOI2012迷失游乐园(树形dp+环套树+概率期望)

    考虑树的部分分怎么做.令f[i]为i向子树内走的期望路径长度,转移比较显然.算答案时先把其父亲的答案弄好就可以统计自己的答案了. 环套树也类似.树里直接dp,对环上点暴力考虑环上的每条路径,算完后再在 ...

  3. [BZOJ2878][NOI2012]迷失游乐园(环套树DP+概率)

    推荐讲解:https://www.cnblogs.com/Tunix/p/4561493.html 首先考虑树的情况,就是经典的树上概率DP.先DP出down表示从这个点向儿子走能走的期望长度,再DP ...

  4. [luogu2081 NOI2012] 迷失游乐园 (树形期望dp 基环树)

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

  5. BZOJ2878 [Noi2012]迷失游乐园 【基环树 + 树形dp + 期望dp】

    题目链接 BZOJ2878 题解 除了实现起来比较长,思维难度还是挺小的 观察数据范围发现环长不超过\(20\),而我们去掉环上任何一个点就可以形成森林 于是乎我们枚举断掉的点,然后只需求出剩余每个点 ...

  6. bzoj2878 [Noi2012]迷失游乐园 [树形dp]

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

  7. BZOJ2878 [Noi2012]迷失游乐园

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...

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

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

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

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

随机推荐

  1. Java普通员工管理系统

    login GUI界面(登录) package 普通员工管理系统; import java.awt.event.ActionEvent; import java.awt.event.ActionLis ...

  2. 【kotlin】报错:required:LIst<XXX> found:List<Unit>此类型的问题

    出现问题如下: 解决方式如下: 解决思路:上面报出来的错误很明显,就是说想要的是List<XXX>类型但是给的却是List<Unit>类型,给的不是它想要的嘛 关键就是解决问题 ...

  3. 【面试 springMVC】【第四篇】springMVC的一些问题

    1.springMVC的工作流程是什么样的 1.用户请求到达 2.DispatcherServlet接收请求,发送给处理器映射器 3.处理器映射器handlerMapping,处理找到对应处理器,返回 ...

  4. 【Todo】Java的JIT机制

    先是参考了这篇说的不怎么详细的文章<Java的JIT机制>(Link) JIT是just in time,即时编译技术.使用该技术,能够加速java程序的执行速度. 通常javac将程序源 ...

  5. winform窗体继承泛型类时,设计器无法使用解决办法

    当我们使用winform程序时,winform窗体程序和控件程序都是可以通过设计器进行控件拖拽的,但如果我们继承了一个带有泛型的form基类.那么设计器是无法使用的. 目前我没有找到根本解决的办法,但 ...

  6. c程序设计语言第一章4

    (昨天网络出现了问题,导致这篇没来得及上传,再次补上,今晚照常上传笔记) 练习1.19编写函数r e v e r s e ( s )将字符串s中的字符顺序颠倒过来.使用该函数编写一个程序,每次颠倒一个 ...

  7. UVa 12377 - Number Coding

    题目:一个数能够用一种素数元素的个数表示的形式,43560=23×32×51×112表示成41223: 第一个数是素因子的种类,第二个是每一个素因子的个数递增排列.给你一个这样的形式的串, 问原来的数 ...

  8. 读懂这些spring boot的核心注解,快速配置完成项目搭建

    在spring boot中,摒弃了spring以往项目中大量繁琐的配置,遵循约定大于配置的原则,通过自身默认配置,极大的降低了项目搭建的复杂度.同样在spring boot中,大量注解的使用,使得代码 ...

  9. Eureka vs Zookeeper

    著名的CAP理论指出,一个分布式系统不可能同时满足C(一致性).A(可用性)和P(分区容错性).由于分区容错性在是分布式系统中必须要保证的,因此我们只能在A和C之间进行权衡.在此Zookeeper保证 ...

  10. openwrt mt7620 内存大小检测

    单独编译内核: make V=s target/linux/install 相调函数调用流程: init/main.c : start_kernel() -> setup_arch(&c ...