【NOI2012】迷失游乐园
题目链接:迷失游乐园(BZOJ) 迷失游乐园(Luogu)
独立完成的题,写一发题解纪念一波~
模拟完样例大概可以知道是道树形DP了。
观察数据范围,发现是基环树,至少会有一个环。
先从树的部分开始考虑,如果没有环,怎么DP呢?
先选取一个点为根,f[i]表示从i节点出发走到其子树的路径期望长度。
那么f[x]= sum(f[son]+w[i])/(rd[x]-1),w[i]为son到x的边长,rd[x]为x的度数,当然如果到了根节点,就不必要减1。
然后再换根一波,统计答案就可以了。换根时注意节点度数的处理就行。
这样就能轻松拿到50分的良心部分分。
如果是基环树呢?
习惯把基环树看成一个“细菌”,把环放正中间考虑。

每一个在环上的点都连接着一个子树,先用前面树形DP的方法对每部分子树进行求解,先不换根。
对于环上每个点,可以逆时针走,也可以顺时针走,所以枚举它左右两条边断掉,拆成链。
在链上推一遍就可以得到从这个点往右或往左走的路径期望长。(环上点数量很少,复杂度在允许的范围内)
用这两种期望长度再去更新这个点,然后跑到这个点对应的子树去换根、统计答案。
算期望除以点度数时比较繁琐,写的时候要小心。
代码~
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm> #define For(i,a,b) for(register int i=a;i<=b;++i)
#define Dwn(i,a,b) for(register int i=a;i>=b;--i)
#define Re register
#define Db double using namespace std; const int N=1e5+; int head[N],nxt[N*],v[N*],cnt=;
Db f[N],w[N*],rd[N],z,ans=,Dn;
int n,x,y,m;
bool Fcr[N],vis[N],Ffd=; inline void read(int &v){
v=;
char c=getchar();
while(c<''||c>'')c=getchar();
while(c>=''&&c<='')v=v*+c-'',c=getchar();
}
inline void read(Db &v){
v=;
char c=getchar();
while(c<''||c>'')c=getchar();
while(c>=''&&c<='')v=v*+c-'',c=getchar();
}
void add(int ux,int vx,Db wx){
cnt++; rd[ux]+=;
nxt[cnt]=head[ux]; head[ux]=cnt; v[cnt]=vx; w[cnt]=wx;
cnt++; rd[vx]+=;
nxt[cnt]=head[vx]; head[vx]=cnt; v[cnt]=ux; w[cnt]=wx;
}
void dfsDP(int x,int fa){
for(Re int i=head[x];i;i=nxt[i]){
int vv=v[i]; if(vv==fa)continue;
if(Fcr[vv])continue;
dfsDP(vv,x);
f[x]+=f[vv]+w[i];
}
if(rd[x]>&&fa)f[x]/=(rd[x]-1.0);
if(fa==&&rd[x])f[x]/=rd[x];
}
void dfsFA(int x,int fa){
ans+=f[x]/Dn;
for(Re int i=head[x];i;i=nxt[i]){
int vv=v[i]; if(vv==fa)continue;
if(Fcr[vv])continue;
Db Bfx=f[x]; Db Bfv=f[vv]; Bfx=f[x]*rd[x]-f[vv]-w[i];
if(rd[x]>)Bfx/=(rd[x]-); f[vv]=f[vv]*(rd[vv]-)+Bfx+w[i];
f[vv]/=rd[vv];
dfsFA(vv,x);
f[vv]=Bfv;
}
}
int st[N],top=,tot=-,cr[N][];
Db dsf[N],dcr[N][],fx[N][];
void dfsCIR(int x,int fa){
vis[x]=; st[++top]=x;
for(Re int i=head[x];i;i=nxt[i]){
int vv=v[i]; if(vv==fa)continue;
if(vis[vv]){
Ffd=;
while(st[top]!=vv){
int stx=st[top--];
cr[++tot][]=stx; dcr[tot][]=dsf[stx]; Fcr[stx]=;
}
cr[++tot][]=vv; dcr[tot][]=w[i]; Fcr[vv]=;
return;
}
dsf[vv]=w[i];
dfsCIR(vv,x);
if(Ffd)return;
}
top--;
}
void getF12(int pos,int now){
int p=pos+;
Db Fx=;
if(p>tot)p=;
Fx=f[cr[p][now]];
do{
Fx+=dcr[p][now];
p++; if(p>tot)p=;
if(p==pos)break;
int cx=cr[p][now];
Db Fcx=f[cx]*(rd[cx]-);
Fx=(Fx+Fcx)/(rd[cx]-);
}while(p!=pos);
fx[ cr[pos][now] ][now]=Fx;
} int main(){
read(n); read(m); Dn=n;
memset(Fcr,,sizeof(Fcr));
memset(vis,,sizeof(vis));
For(i,,m){
read(x); read(y); read(z);
add(x,y,z);
}
if(m<n){
dfsDP(,); dfsFA(,);
printf("%.05lf",ans);
return ;
}
dfsCIR(,);
For(i,,tot){
rd[cr[i][]]-=;
dfsDP(cr[i][],);
rd[cr[i][]]+=;
}
For(i,,tot){
cr[i][]=cr[tot-i][];
if(i!=tot)dcr[i][]=dcr[tot-i-][];
else dcr[i][]=dcr[tot][];
} For(i,,tot){
getF12(i,); getF12(i,);
}
For(i,,tot){
int cx=cr[i][];
f[cx]*=(rd[cx]-);
f[cx]+=fx[cx][]+fx[cx][];
f[cx]/=rd[cx];
dfsFA(cx,);
}
printf("%.05lf",ans);
return ;
}
【NOI2012】迷失游乐园的更多相关文章
- BZOJ 2878: [Noi2012]迷失游乐园( 树形dp )
		一棵树的话直接树形dp(求出往下走和往上走的期望长度). 假如是环套树, 环上的每棵树自己做一遍树形dp, 然后暴力枚举(环上的点<=20)环上每个点跑经过环上的路径就OK了. -------- ... 
- 【BZOJ 2878】 2878: [Noi2012]迷失游乐园 (环套树、树形概率DP)
		2878: [Noi2012]迷失游乐园 Description 放假了,小Z觉得呆在家里特别无聊,于是决定一个人去游乐园玩.进入游乐园后,小Z看了看游乐园的地图,发现可以将游乐园抽象成有n个景点.m ... 
- [bzoj2878][Noi2012]迷失游乐园(基环树dp)
		[bzoj2878][Noi2012]迷失游乐园(基环树dp) bzoj luogu 题意:一颗数或是基环树,随机从某个点开始一直走,不走已经到过的点,求无路可走时的路径长期望. 对于一棵树: 用两个 ... 
- NOI2012 : 迷失游乐园
		终于补完NOI2012了好开心~ 题目大意:给定一棵树或者环套外向树,求出从中随机选一条简单路径的期望长度,环上点数不超过20. 设 d[x]表示x的度数,ch[x]表示x孩子个数 up[x]表示x向 ... 
- 2878: [Noi2012]迷失游乐园 - BZOJ
		Description 放假了,小Z觉得呆在家里特别无聊,于是决定一个人去游乐园玩.进入游乐园后,小Z看了看游乐园的地图,发现可以将游乐园抽象成有n个景点.m条道路的无向连通图,且该图中至多有一个环( ... 
- 【BZOJ 2878】 [Noi2012]迷失游乐园
		Description 放假了,小Z觉得呆在家里特别无聊,于是决定一个人去游乐园玩.进入游乐园后,小Z看了看游乐园的地图,发现可以将游乐园抽象成有n个景点.m条道路的无向连通图,且该图中至多有一个环( ... 
- BZOJ2878 [Noi2012]迷失游乐园
		本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ... 
- bzoj2878 [Noi2012]迷失游乐园 [树形dp]
		Description 放假了,小Z认为呆在家里特别无聊.于是决定一个人去游乐园玩. 进入游乐园后.小Z看了看游乐园的地图,发现能够将游乐园抽象成有n个景点.m条道路的无向连通图,且该图中至多有一个环 ... 
- [luogu2081 NOI2012] 迷失游乐园 (树形期望dp 基环树)
		传送门 题目描述 放假了,小Z觉得呆在家里特别无聊,于是决定一个人去游乐园玩. 进入游乐园后,小Z看了看游乐园的地图,发现可以将游乐园抽象成有n个景点.m条道路的无向连通图,且该图中至多有一个环(即m ... 
- bzoj 2878: [Noi2012]迷失游乐园
		#include<iostream> #include<cstring> #include<cstdio> #define M 100005 #define ld ... 
随机推荐
- Django 后台管理 之登录和注销
			Session: session是服务器端生成保存的一个键值对 , session内部机制依赖于cookie . 用户登录后返回给客户端一个随机字符串,客户端带着随机字符串访问服务器,用于验证 ... 
- 【html学习整理】常用标签
			什么是html 超文本标记语言 html语法规则 所有的命令放到<> 大部分成对存在,以<tag>开始,</tag>结束 网页的基本框架,常用的标记 & ... 
- C# 关于线程锁lock的使用方法
			C# 关于线程锁lock的使用方法 原创 2016年09月02日 10:07:05 标签: c# / 线程 / 锁 / lock 11937 在多线程编程中,可能会有许多线程并发的执行一段代码(代码块 ... 
- 虚拟化网络之OpenvSwitch
			OpenvSwitch简称OVS,官网(http://openvswitch.org/) OVS是一个高质量.多层的虚拟交换软件,即虚拟交换机. OpenvSwitch的见的相关组件: ovs-vsw ... 
- RQNOJ 169 最小乘车费用:水dp
			题目链接:https://www.rqnoj.cn/problem/169 题意: 给出行驶1-10公里的费用(所有车一样),可以倒车,问行驶n公里的最小费用. 题解: 大水题... (=´ω`=) ... 
- python基础-大杂烩
			random()随机函数 import random print(random.choice('abcdefghij')) #随机取这些字母 print(random.choice(['apple', ... 
- python基础-文本操作
			文件IO #文件的基本操作 1.在python中你可以用file对象做大部分的文件操作 2.一般步骤: 先用python内置的open()函数打开一个文件,并创建一个file对象, 然后调用相关方法进 ... 
- listen 78
			Struggling Young Readers Like Kindles Kindles, Nooks and other e-readers catch flack for threatening ... 
- Quartz.Net初探
			想必大家在工作中经常会遇到这样类似的需求,在某个时间或者需要不间断的执行某个业务动作去满足任务需求.例如,我们写了一个job,定时去处理一些任务,在没有了解到Quartz.Net之前,我是这样做的,进 ... 
- codeforces 706B B. Interesting drink(二分)
			题目链接: B. Interesting drink 题意: 给出第i个商店的价钱为x[i],现在询问mi能在多少个地方买酒; 思路: sort后再二分; AC代码: #include <ios ... 
