【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 ...
随机推荐
- Database: index
The whole point of having an index is to speed up search queries by essentially cutting down the num ...
- 算法(Algorithms)第4版 练习 1.3.21
方法实现: //1.3.21 /** * find if some node in the list has key as its item field * * @param list the lin ...
- Uncaught TypeError: Illegal invocation解决
jquery中报了这个错,仔细一看,有个使用ajax的地方,其中有个参数是从页面某个文本框获取的,本应该 $('#id').value ,被我写成了 $('id') .所以报错,目前已解决.
- HTML/CSS实现的搜索框
谷歌和百度首页的搜索框都是<input>+<button>模式的,bing的搜索框感觉要好点儿.简言之,就是将提交按钮放到<input>中,其实这是做不到的,只能伪 ...
- python 3 - 写一个注册的程序,账号和密码都存在文件里面
choice = input('请输入你的选择:1,注册2.删除用户3.登录') #注册 输入 账号 密码 密码确认 # #需要校验用户是否存在,两次输入的密码,是否一致,为空的情况 #账号和密码都存 ...
- 《java编程思想》:第五章,初始化与清理
知识点整理: 1.从概念上讲,‘初始化’与‘创建’是彼此独立的,但是在Java中,两者被捆绑在一起,不可分离. 2.区分重载的方法:每个重载的方法都有一个独一无二的参数类型列表. 甚至参数顺序的不同也 ...
- linux 多线程编程-读写者问题
#include <cstdio> #include <pthread.h> #include <unistd.h> ]; int i,j; pthread_rwl ...
- [JSOI 2018] 潜入行动
[题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=5314 [算法] 考虑dp , 用f[i][j][0 / 1][0 / 1]表示以i为 ...
- 自己实现的vector
#include <iostream> #include <memory> using std::cout; using std::endl; using std::alloc ...
- Springboot学习七 spring的一些注解
一 事务控制 @Service public class CityServiceImpl implements CityService { @Autowired private CityMapper ...