【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 ...
随机推荐
- bind、call、apply的区别与实现原理
1.简单说一下bind.call.apply的区别 三者都是用于改变函数体内this的指向,但是bind与apply和call的最大的区别是:bind不会立即调用,而是返回一个新函数,称为绑定函数,其 ...
- error:Flash Download failed-“Cortex-M3”,“Programming Algorithm”【转】
本文转载自:http://www.yfrobot.com/thread-11763-1-1.html 最近安装了KEIL5,在使用KEIL5和JLIN实现在线调试功能时,一定会在Utilities选项 ...
- excel根据数据源变化的动态图表
http://www.excelhome.net/lesson/article/excel/1798.html 这个链接讲的可以.
- html5--2.7新的布局元素(4)-time
html5--2.7新的布局元素(4)-time 学习要点 了解微格式的概念 掌握time元素的用法 微格式的概念 HTML5中的微格式,是一种利用HTML5中的新标签对网页添加附加信息的方法,附加信 ...
- laravel 在apache或nginx的配置
laravel 下载后,如何运行起来呢,根据自己的应用,记录了几个关键点: 1.apache 配置: 打开http.conf文件,将mod_rewrite前面的#去掉(启用重写模块): 2.nginx ...
- sphinx 全文搜索引擎
sphinx的安装与配置 --------------------------------------------------------------------------------------- ...
- linux命令学习笔记(31): /etc/group文件详解
Linux /etc/group文件与/etc/passwd和/etc/shadow文件都是有关于系统管理员对用户和用户组管理时相关的文件. linux /etc/group文件是有关于系统 管理员对 ...
- 「SHOI2002」「LuoguP1291」百事世界杯之旅(UVA10288 Coupons)(期望,输出
题目描述 “……在2002年6月之前购买的百事任何饮料的瓶盖上都会有一个百事球星的名字.只要凑齐所有百事球星的名字,就可参加百事世界杯之旅的抽奖活动,获得球星背包,随声听,更克赴日韩观看世界杯.还不赶 ...
- CodeForces - 123E Maze
http://codeforces.com/problemset/problem/123/E 题目翻译:(翻译来自: http://www.cogs.pw/cogs/problem/problem.p ...
- lsnrctl启动报错,Linux Error: 29: Illegal seek
[oracle@phydb admin]$ lsnrctl startLSNRCTL for Linux: Version 11.2.0.1.0 - Production on 15-SEP-2014 ...