bzoj2878 [Noi2012]迷失游乐园——概率期望DP
题目: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的更多相关文章
- [bzoj2878][Noi2012]迷失游乐园(基环树dp)
[bzoj2878][Noi2012]迷失游乐园(基环树dp) bzoj luogu 题意:一颗数或是基环树,随机从某个点开始一直走,不走已经到过的点,求无路可走时的路径长期望. 对于一棵树: 用两个 ...
- BZOJ2878 NOI2012迷失游乐园(树形dp+环套树+概率期望)
考虑树的部分分怎么做.令f[i]为i向子树内走的期望路径长度,转移比较显然.算答案时先把其父亲的答案弄好就可以统计自己的答案了. 环套树也类似.树里直接dp,对环上点暴力考虑环上的每条路径,算完后再在 ...
- [BZOJ2878][NOI2012]迷失游乐园(环套树DP+概率)
推荐讲解:https://www.cnblogs.com/Tunix/p/4561493.html 首先考虑树的情况,就是经典的树上概率DP.先DP出down表示从这个点向儿子走能走的期望长度,再DP ...
- [luogu2081 NOI2012] 迷失游乐园 (树形期望dp 基环树)
传送门 题目描述 放假了,小Z觉得呆在家里特别无聊,于是决定一个人去游乐园玩. 进入游乐园后,小Z看了看游乐园的地图,发现可以将游乐园抽象成有n个景点.m条道路的无向连通图,且该图中至多有一个环(即m ...
- BZOJ2878 [Noi2012]迷失游乐园 【基环树 + 树形dp + 期望dp】
题目链接 BZOJ2878 题解 除了实现起来比较长,思维难度还是挺小的 观察数据范围发现环长不超过\(20\),而我们去掉环上任何一个点就可以形成森林 于是乎我们枚举断掉的点,然后只需求出剩余每个点 ...
- bzoj2878 [Noi2012]迷失游乐园 [树形dp]
Description 放假了,小Z认为呆在家里特别无聊.于是决定一个人去游乐园玩. 进入游乐园后.小Z看了看游乐园的地图,发现能够将游乐园抽象成有n个景点.m条道路的无向连通图,且该图中至多有一个环 ...
- BZOJ2878 [Noi2012]迷失游乐园
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...
- 【BZOJ 2878】 2878: [Noi2012]迷失游乐园 (环套树、树形概率DP)
2878: [Noi2012]迷失游乐园 Description 放假了,小Z觉得呆在家里特别无聊,于是决定一个人去游乐园玩.进入游乐园后,小Z看了看游乐园的地图,发现可以将游乐园抽象成有n个景点.m ...
- BZOJ 2878: [Noi2012]迷失游乐园( 树形dp )
一棵树的话直接树形dp(求出往下走和往上走的期望长度). 假如是环套树, 环上的每棵树自己做一遍树形dp, 然后暴力枚举(环上的点<=20)环上每个点跑经过环上的路径就OK了. -------- ...
随机推荐
- 输出重定向、cat、系统别名、查看指定行、时间戳
1.touch命令:如果文件不存在则创建,如存在则更新时间戳;2.除了echo有向文件写入内容的功能,cat也可以; cat > hehe # 输出重定向 cat >> hehe # ...
- Leetcode 数组问题:删除排序数组内的重复项
问题描述: 给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度. 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成 ...
- Java重写父类使用@Override时出现The method destroy() of type xxx must override a superclass method的问题解决
解决方法: 1.把JDK版本改成1.6以上的. 2.把Compiler改成1.6以上的. 关于这两者的区别,参考:http://www.cnblogs.com/EasonJim/p/6741682.h ...
- Cesium调用Geoserver发布的 WMS、WFS服务
1 GeoServer服务发布 1.1 WMS服务 下载GeoServer安装版安装,同时安装geopackage扩展,以备使用.使用XX地图下载器下载地图,导出成GeoPackage地图文件. (1 ...
- Linux索引节点(Inode:no space for device)用满导致的一次故障
问题描写叙述 在storm測试环境集群上上nimbus和supervisor自己主动挂调.重新启动时显示no space for device,也不能创建,加入文件及文件夹,df -h查看 ilesy ...
- 自动化运维工具Fabric - 密码管理(env.password and ssh key)
在使用 Fabric 的过程中,如果大批量服务器处理的话,我们就需要针对配置主机的密码,每台主机的密码相同还好,不同的话,就需要针对不同的主机做配置了,以下有两种配置方式 注:本文主要参考官方文档 P ...
- 零基础学python-3.2 变量赋值
这一节我们来具体展开变量赋值 1.以下我们举各种赋值的样例 anInt=12 anFloat=2.2 anStr='string' aList=['a','a','a'] anArray=(1,2,3 ...
- SolidEdge 如何绘制断裂剖视图 局部剖视图
1 点击局部放大图,然后点击绘制按钮,然后点击选择要绘制的视图 2 绘制封闭的局部剖视图的剖面线(必须封闭,点击最后一个点封闭之后会变成蓝色虚线) 3 修改深度(不一定要在下图的右下角修改深度 ...
- HDU 3118 Arbiter 判定奇圈
题目来源:pid=3118">HDU 3118 Arbiter 题意:翻译过来就是不能有奇圈 每走一步状态会变化 当他回到起点时假设和原来的状态不一样 可能会死 求至少去掉多少条边能够 ...
- C#json数据的序列化和反序列化(将数据转换为对象或对象集合)
引用 System.Runtime.Serialization.Json