传送门

题目描述

放假了,小Z觉得呆在家里特别无聊,于是决定一个人去游乐园玩。

进入游乐园后,小Z看了看游乐园的地图,发现可以将游乐园抽象成有n个景点、m条道路的无向连通图,且该图中至多有一个环(即m只可能等于n或者n-1)。小Z现在所在的大门也正好是一个景点。小Z不知道什么好玩,于是他决定,从当前位置出发,每次随机去一个和当前景点有道路相连的景点,并且同一个景点不去两次(包括起始景点)。贪玩的小Z会一直游玩,直到当前景点的相邻景点都已经访问过为止。

小Z所有经过的景点按顺序构成一条非重复路径,他想知道这条路径的期望长度是多少?

小Z把游乐园的抽象地图画下来带回了家,可是忘了标哪个点是大门,他只好假设每个景点都可能是大门(即每个景点作为起始点的概率是一样的)。同时,他每次在选择下一个景点时会等概率地随机选择一个还没去过的相邻景点。

【评分方法】本题没有部分分,你程序的输出只有和标准答案的差距不超过0.01时,才能获得该测试点的满分,否则不得分。

输入输出格式

输入格式:

第一行是两个整数n和m,分别表示景点数和道路数。 接下来行,每行三个整数Xi, Yi, Wi,分别表示第i条路径的两个景点为Xi, Yi,路径长Wi。所有景点的编号从1至n,两个景点之间至多只有一条道路。

输出格式:

共一行,包含一个实数,即路径的期望长度,保留五位小数。

输入输出样例

输入样例#1:

4 3

1 2 3

2 3 1

3 4 4

输出样例#1:

6.00000000

说明

【样例解释】样例数据中共有6条不同的路径: 路径 长度 概率

路径 长度 概率

1-->4 8 1/4

2-->1 3 1/8

2-->4 5 1/8

3-->1 4 1/8

3-->4 4 1/8

4-->1 8 1/4

因此期望长度 = 8/4 + 3/8 + 5/8 + 4/8 + 4/8 + 8/4 = 6.00

【评分方法】本题没有部分分,你程序的输出只有和标准答案的差距不超过0.01时,才能获得该测试点的满分,否则不得分。

【数据规模和约定】对于100%的数据,1 <= Wi <= 100。

测试点编号 n m 备注

1 n=10 m = n-1 保证图是链状

2 n=100 只有节点1的度数大于2

3 n=1000 /

4 n=100000 /

5 n=100000 /

6 n=10 m = n /

7 n=100 环中节点个数<=5

8 n=1000 环中节点个数<=10

9 n=100000 环中节点个数<=15

10 n=100000 环中节点个数<=20

题解

这个题细节挺多的(调了好长时间)

先考虑树形状态下,由于是树那么只会是 从上往下走 或 从下往上 或 从下往上再往下qwq

那么先考虑从上往下 down[u]表示u从上往下的期望路程 son[u]表示u的子节点数

那么有\(down[u]=\frac{\sum down[v]+dis(u,v)}{son[u]}\)

其中v是u的子节点 显然可以一遍dfs解决

在考虑从下往上 up[u]表示u从下往上的期望路程 pre为u的父节点

nfa[pre]=1表示pre有父节点 =0则没有

\(up[u]=\frac{down[pre]*son[pre]-down[u]-dis[pre,u]+up[pre]*nfa[pre]}{son[pre]-1+nfa[pre]}\)

这表示父节点除了下到u之外情况的期望值除以所有可能情况

在式子中表示为pre原来的全部期望值减去下到u的期望值加上(如果有父节点)到pre父节点的期望值

这实际上等价于u这个点上到pre的期望值除以所有情况(到父亲的父亲去或其他子节点) 同样一遍dfs解决

最后将每个节点的期望路程统计出来求出平均值即可

那么我们在树的基础上在考虑一下有一个环的树

我们发现题目中说环上点的个数最多只有20个,那么显然我们可以暴力求解。。

首先找出环,然后以环上每个点为起点跑一次树求down的过程

up的值显然不能直接求,因为有可能从环上跑到别的树上去

所以我们需要在环上进行一些处理

仍然是枚举环上所有的点,我们现在要求上到环上一点u之后的期望路程

我们先要清楚环上一点(x)到下一点(y)的概率

\(p[y]=p[x]*\frac{1}{son[x]+1}\)

所以不到下一个点而是下到x的子树中的概率

\(P=\frac{son[x]}{son[x]+1}\)

然后我们记录u到x的距离为d,则u到x(并且进x的子树中)的期望值为

\(up[u]+=\frac{(down[x]+d)*son[x]}{son[x]+1}\)

枚举u和x我们就得到了环上每个点的up值

然后再以每一个环上的点为根用树上的up值更新方法最终就能求出所有点的up值

最后的最后跟树一样统计每个节点的期望值求平均即可

好像是有点麻烦

code:

//By Menteur_Hxy
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#define E(i,u) for(register int i=head[u];i;i=nxt[i])
#define F(i,a,b) for(register int i=(a);i<=(b);i++)
#define add(a,b,c) nxt[++cnt]=head[a],to[cnt]=b,w[cnt]=c,head[a]=cnt
#define insert(a,b,c) add(a,b,c),add(b,a,c)
using namespace std; int rd() {
int x=0,f=1; char c=getchar();
while(!isdigit(c)) {if(c=='-') f=-f; c=getchar();}
while(isdigit(c)) x=(x<<1)+(x<<3)+c-48,c=getchar();
return x*f;
} const int N=100010;
int n,m,cnt;
int nxt[N<<1],to[N<<1],w[N<<1],head[N];
int snum[N],dis[N],vis[N],nfa[N];
double up[N],down[N],ans; void dfs_down(int u) {
vis[u]=1; int v;
E(i,u) if(!vis[to[i]])
v=to[i],dis[v]=w[i],dfs_down(v),snum[u]++,down[u]+=down[v]+w[i];
if(snum[u]) down[u]/=double(snum[u]); vis[u]=0;
} void dfs_up(int u,int pre) {
vis[u]=1; if(pre) nfa[u]=1;
if((snum[pre]-1+nfa[pre])&&pre)
up[u]+=(down[pre]*snum[pre]-down[u]-dis[u]+up[pre]*nfa[pre])/double(snum[pre]-1+nfa[pre]);
E(i,u) if(!vis[to[i]]) up[to[i]]+=w[i],dfs_up(to[i],u);
} int tot,len;
int dfn[N],cirn[N],cire[N],fa[N];
bool flag,inc[N];
void tarjan(int u,int pre) {
if(flag) return ;
dfn[u]=++tot; fa[u]=pre;
E(i,u) { int v=to[i];
if(v==pre or flag) continue;
if(!dfn[v]) dis[v]=w[i],tarjan(v,u);
else if(dfn[v]>dfn[u]) {
cire[1]=w[i];
for(int now=v;now!=fa[u];now=fa[now])
cirn[++len]=now,cire[len+1]=dis[now],nfa[now]=2,vis[now]=1;
flag=1;
}
}
} void cir_calc(int u,int k,int reg) {
double t=0.5,d=0;
F(i,1,len-1) {
if(reg==-1) d+=cire[k]; k+=reg;
if(!k) k=len; if(k==len+1) k=1;
if(reg==1) d+=cire[k];
if(i==len-1) up[u]+=t*(down[cirn[k]]+d);
else up[u]+=t*(down[cirn[k]]+d)*snum[cirn[k]]/double(snum[cirn[k]]+1);
t/=double(snum[cirn[k]]+1);
}
} void cireework() {
tarjan(1,0);
F(i,1,len) dfs_down(cirn[i]),vis[cirn[i]]=1;
F(i,1,len) cir_calc(cirn[i],i,1),cir_calc(cirn[i],i,-1);
F(i,1,len) dfs_up(cirn[i],0);
} int main() {
n=rd(),m=rd();
F(i,1,m) {
int a=rd(),b=rd(),c=rd();
insert(a,b,c);
}
if(m==n-1) dfs_down(1),dfs_up(1,0);
else cireework();
F(i,1,n) ans+=(double)(down[i]*snum[i]+up[i]*nfa[i])/double(snum[i]+nfa[i]);
ans/=double(n);
printf("%.5lf",ans);
return 0;
}

[luogu2081 NOI2012] 迷失游乐园 (树形期望dp 基环树)的更多相关文章

  1. bzoj2878 [Noi2012]迷失游乐园——概率期望DP

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2878 这个博客写得很好:https://www.cnblogs.com/qt666/p/72 ...

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

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

  3. Luogu P2081 [NOI2012]迷失游乐园 | 期望 DP 基环树

    题目链接 基环树套路题.(然而各种错误调了好久233) 当$m=n-1$时,原图是一棵树. 先以任意点为根做$dp$,求出从每一个点出发,然后只往自己子树里走时路径的期望长度. 接着再把整棵树再扫一遍 ...

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

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

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

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

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

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

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

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

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

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

  9. Hdu第八场 树形dp+基环树

    Card Game 每个牌背面的数字朝正面的数字连一条有向边 则题目变为问你最少翻转多少次 能使得每个数字的入度不超过1 首先判断图中每个连通块是不是树或者基环树 因为只有树或者基环树能使得每个点的入 ...

随机推荐

  1. vs code--snippet与快速提示

    因为快速语法提示和建议冲突,所以要么禁用语法提示,要么禁用建议 Note that quick suggestions and Tab completion might interfere becau ...

  2. jQuery学习之开篇

    吐槽 近期比較烦,对于一个前端白痴来说,工作方向突然转向前端这块着实让人蛋疼无比.前段时间简单的学习了下EasyUI,算是对其有一个简单的认知了吧.EasyUI的研究过程中发现,假设没有掌握JS.JQ ...

  3. 使用Python生成源文件的两种方法

    利用Python的字符串处理模块,开发者能够编写脚本用来生成那些格式同样的C.C++.JAVA源程序.头文件和測试文件,从而避免大量的反复工作. 本文概述两种利用Python string类生成jav ...

  4. 64位win7中使用vs2013为python3.4安装pycrypto-2.6.1插件报Unable to find vcvarsall.bat异常解决方式

    问题描写叙述: 64位win7中使用vs2013为python3.4.2安装pycrypto-2.6.1插件报Unable to find vcvarsall.bat. 问题分析: 1.源代码分析,查 ...

  5. leetCode(30):Sort Colors

    Given an array with n objects colored red, white or blue, sort them so that objects of the same colo ...

  6. elasticsearch indices.recovery 流程分析(索引的_open操作也会触发recovery)——主分片recovery主要是从translog里恢复之前未写完的index,副分片recovery主要是从主分片copy segment和translog来进行恢复

    摘自:https://www.easyice.cn/archives/231 elasticsearch indices.recovery 流程分析与速度优化 目录 [隐藏] 主分片恢复流程 副本分片 ...

  7. DNS同时占用UDP和TCP端口53——传输数据超过512时候用tcp,DNS服务器可以配置仅支持UDP查询包

    DNS同时占用UDP和TCP端口53是公认的,这种单个应用协议同时使用两种传输协议的情况在TCP/IP栈也算是个另类.但很少有人知道DNS分别在什么情况下使用这两种协议. 先简单介绍下TCP与UDP. ...

  8. HDU2080 夹角有多大2

    2019-05-17 15:00:09 加油加油,fightting !!! 这道题不知道acos()函数,acos()返回的是弧度,转化成度数要 / PI * 180 也没有想到通过向量 但是想到了 ...

  9. java三大版本解析

    JAVA三大版本代表着JAVA技术的三个应用领域:JAVASE.JAVAME.JAVAEE. JAVA以前很长一段时间被称为JAVA2,所以现在很多人习惯称为J2SE.J2ME.J2EE,它们表示的含 ...

  10. WPF黑色背景下常用控件样式

    平时工作用 自己整理的 代码等找到合适的上传空间在进行同步