题目链接

BZOJ2878

题解

除了实现起来比较长,思维难度还是挺小的

观察数据范围发现环长不超过\(20\),而我们去掉环上任何一个点就可以形成森林

于是乎我们枚举断掉的点,然后只需求出剩余每个点为根的答案

设\(f[i]\)表示从\(i\)出发等概率走向子树的期望步数

如果\(i\)为根就是我们所需的答案

首先求出\(f[i]\),然后用换根法扫一遍便求出每个点为根的答案

对于我们枚举的环上的点\(u\),答案自然就是

\[\sum\limits_{(u,v) \in E} \frac{f[v] + w_{(u,v)}}{de[u]}
\]

对于点\(u\)外向树中的点,再用一次换根法就可以将\(u\)的答案转移进去,然后求出的就是真实的答案了

复杂度\(O(20n)\)

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<map>
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define mp(a,b) make_pair<int,int>(a,b)
#define cls(s) memset(s,0,sizeof(s))
#define cp pair<int,int>
#define LL long long int
using namespace std;
const int maxn = 200005,maxm = 100005,INF = 1000000000;
inline int read(){
int out = 0,flag = 1; char c = getchar();
while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
return out * flag;
}
int n,m,de[maxn];
int h[maxn],ne = 1;
struct EDGE{int to,nxt; double w;}ed[maxn << 1];
inline void build(int u,int v,double w){
ed[++ne] = (EDGE){v,h[u],w}; h[u] = ne;
ed[++ne] = (EDGE){u,h[v],w}; h[v] = ne;
de[u]++; de[v]++;
}
double f[maxn],up[maxn],ans[maxn];
int fa[maxn],Out[maxn],rt;
int c[maxn],ci,vis[maxn],inc[maxn],at[maxn];
void dfs1(int u){
f[u] = 0; vis[u] = true;
if (u != rt && de[u] == 1) return;
if (!de[u]) return;
double d = (u == rt) ? 1.0 / de[u] : 1.0 / (de[u] - 1);
Redge(u) if ((to = ed[k].to) != fa[u] && !Out[to]){
fa[to] = u; up[to] = ed[k].w; dfs1(to);
f[u] += (f[to] + ed[k].w) * d;
}
}
void dfs2(int u){
if (u != rt){
int v = fa[u];
if (de[v] == 1) f[u] = f[u] * (de[u] - 1) / de[u] + up[u] / de[u];
else {
double tmp = f[v] * de[v] / (de[v] - 1) - (f[u] + up[u]) / (de[v] - 1);
f[u] = f[u] * (de[u] - 1) / de[u] + (tmp + up[u]) / de[u];
}
}
Redge(u) if ((to = ed[k].to) != fa[u] && !Out[to])
dfs2(to);
}
void solve1(){
rt = 1;
dfs1(1);
dfs2(1);
double ans = 0;
REP(i,n) ans += f[i];
printf("%.5lf\n",ans / n);
}
void dfs3(int u){
vis[u] = true;
Redge(u) if ((to = ed[k].to) != fa[u]){
if (vis[to]){
if (ci) continue;
for (int i = u; i != to; i = fa[i]) c[++ci] = i,inc[i] = true;
c[++ci] = to; inc[to] = true;
}
else fa[to] = u,dfs3(to);
}
}
void dfs4(int u){
f[u] = 0;
if (de[u] == 1) return;
double d = 1.0 / (de[u] - 1);
Redge(u) if ((to = ed[k].to) != fa[u] && !Out[to]){
fa[to] = u; up[to] = ed[k].w; dfs4(to);
f[u] += (f[to] + ed[k].w) * d;
}
}
void dfs5(int u){
int v = fa[u];
if (de[v] == 1) f[u] = f[u] * (de[u] - 1) / de[u] + up[u] / de[u];
else {
double tmp = f[v] * de[v] / (de[v] - 1) - (f[u] + up[u]) / (de[v] - 1);
f[u] = f[u] * (de[u] - 1) / de[u] + (tmp + up[u]) / de[u];
}
ans[u] = f[u];
Redge(u) if ((to = ed[k].to) != fa[u])
dfs5(to);
}
void work(int u){
Out[u] = true;
REP(i,n) vis[i] = false,at[i] = false; vis[u] = true;
Redge(u){
de[to = ed[k].to]--;
if (!inc[to]) at[to] = true;
}
Redge(u) if (!vis[to = ed[k].to]){
fa[rt = to] = 0;
dfs1(rt);
dfs2(rt);
}
double d = 1.0 / de[u];
Redge(u) ans[u] += (f[to = ed[k].to] + ed[k].w) * d;
f[u] = ans[u];
Redge(u){
de[to = ed[k].to]++;
if (!inc[to]){
rt = to; fa[to] = u; up[to] = ed[k].w;
dfs4(rt);
dfs5(rt);
}
}
Out[u] = false;
}
void solve2(){
dfs3(1);
REP(i,ci) work(c[i]);
double re = 0;
REP(i,n) re += ans[i];
re /= n;
printf("%.5lf\n",re);
}
int main(){
n = read(); m = read(); int a,b,w;
REP(i,m){
a = read(); b = read(); w = read();
build(a,b,w);
}
if (m == n - 1) solve1();
else solve2();
return 0;
}

BZOJ2878 [Noi2012]迷失游乐园 【基环树 + 树形dp + 期望dp】的更多相关文章

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

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

  2. [BZOJ2878][NOI2012]迷失游乐园(环套树DP+概率)

    推荐讲解:https://www.cnblogs.com/Tunix/p/4561493.html 首先考虑树的情况,就是经典的树上概率DP.先DP出down表示从这个点向儿子走能走的期望长度,再DP ...

  3. BZOJ2878 NOI2012迷失游乐园(树形dp+环套树+概率期望)

    考虑树的部分分怎么做.令f[i]为i向子树内走的期望路径长度,转移比较显然.算答案时先把其父亲的答案弄好就可以统计自己的答案了. 环套树也类似.树里直接dp,对环上点暴力考虑环上的每条路径,算完后再在 ...

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

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

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

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

  6. BZOJ2878 [Noi2012]迷失游乐园

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...

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

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

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

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

  9. 洛谷 P1453 城市环路 ( 基环树树形dp )

    题目链接 题目背景 一座城市,往往会被人们划分为几个区域,例如住宅区.商业区.工业区等等.B市就被分为了以下的两个区域--城市中心和城市郊区.在着这两个区域的中间是一条围绕B市的环路,环路之内便是B市 ...

随机推荐

  1. Datawhale MySQL 训练营 Task4 表联结

    学习内容 MySQL别名 列别名,将查询或者筛选出来列用AS 命名,如果有空格则需要引号 '' SELECT xxx AS xxxx FROM WHERE GROUP BY HAVING 表别名, 把 ...

  2. 可道云kodexplorer搭建私有云后的配置优化

    一.上传下载速度优化首先明确可道云没有对上传下载做任何限制,速度快慢和网络环境有关.可道云是基于http上传,所以和其他http上传速度基本一致:可以对比其他web系统或网站说附件上传速度.同其他例如 ...

  3. 吴恩达(Andrew Ng)——机器学习笔记1

    之前经学长推荐,开始在B站上看Andrew Ng的机器学习课程.其实已经看了1/3了吧,今天把学习笔记补上吧. 吴恩达老师的Machine learning课程共有113节(B站上的版本https:/ ...

  4. 服务端模版注入漏洞检测payload整理

    服务端模版注入漏洞产生的根源是将用户输入的数据被模版引擎解析渲染可能导致代码执行漏洞 下表涵盖了java,php,python,javascript语言中可能使用到的模版引擎,如果网站存在服务端模版注 ...

  5. First scrum meeting report - 151017

    提要 今天开会主要是讨论一下北航MOOC客户端的具体要求和每个人的大致分工.会议后来还简单商讨了一下我们app的大致界面框架. 会议地点:大运村KFC 会议时间:2015年10月17日,15:00-1 ...

  6. 20172324 2017-2018-2《程序设计与数据结构》第五周 n!的计算

    20172324 2017-2018-2<程序设计与数据结构>实验2报告 课程:<程序设计与数据结构> 班级: 1723 姓名: 曾程 学号:20172324 实验教师:王志强 ...

  7. 新手学ajax1

       学习的动力是最近想实现servlet向js传值,是html中的js,因为jsp是可以直接调用java 类的,在网上搜索了好久感觉ajax能帮我实现. 以下代码可以实现js向服务器发出一 requ ...

  8. Java jdbc链接 mySQL 写的crud

    1.JDBC(Java Data Base Connectivity java数据库连接)概念: 是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编 ...

  9. 第一次spring冲刺第8天

    针对这几天出现的问题,我们团队做了用户需求讨论. 1.客户类型:工作者为主,其他类型都适用的计算器软件 2.需求与满足:他们想要的是能使用简单,并且适用于工作上 3.满足度:最好后台可以提供意见反馈, ...

  10. JAVA学习IO(1)

    面向过程和面向对象的区别:面向过程:把问题分析成一个一个步骤组成的过程面向对象:从一个问题中分析出各个功能对象,并描述各个功能在整个解决问题的步骤的行为.面向对象的3大特征:封装,继承,多态封装:把多 ...