题目链接

基环树套路题。(然而各种错误调了好久233)

当$m=n-1$时,原图是一棵树。

先以任意点为根做$dp$,求出从每一个点出发,然后只往自己子树里走时路径的期望长度。

接着再把整棵树再扫一遍,求出从每一个点出发时路径的期望长度。

最后再统计一遍答案即可。

当$m=n$时,原图是一棵基环树。

先找到图中那唯一的一个环,然后以环上的每一个节点为根在此节点的子树内做$dp$。

环上节点的数量很少,$dp$之后直接暴力算出从每一个环上节点出发时路径的期望长度。

然后把每一个环上节点的子树扫一遍,求出从每一个点出发时路径的期望长度。

最后再统计一遍答案即可。

#include<iostream>
#include<cstdio>
#include<fstream>
using namespace std;
struct edge
{
int last;
int end;
int weight;
}e[200005];
int n=0,m=0,root=0;
int ne=1,cnt[100005],note[100005];
int tot=0,ring[100005];
int ringdis[100005];
bool flag=false,vis[100005],inring[100005];
double ans=0,f[100005],d[100005];
void NewEdge(int u,int v,int w)
{
ne++;
e[ne].last=note[u];
e[ne].end=v;
e[ne].weight=w;
note[u]=ne;
}
void dfs(int x,int fx)
{
cnt[x]=f[x]=0;
for(int i=note[x];i;i=e[i].last)
{
if(e[i].end==fx||inring[e[i].end]) continue;
dfs(e[i].end,x),cnt[x]++;
}
if(cnt[x]==0) return;
for(int i=note[x];i;i=e[i].last)
{
if(e[i].end==fx||inring[e[i].end]) continue;
f[x]+=e[i].weight+f[e[i].end];
}
f[x]/=cnt[x];
}
void dfss(int x,int fx,int w)
{
if(x==root&&!inring[x]) d[x]=f[x];
else if(x!=root)
{
d[x]=f[x]*cnt[x]/(cnt[x]+1);
if(fx==root&&cnt[fx]==1) d[x]+=(double)w/(cnt[x]+1);
else if(fx==root) d[x]+=((d[fx]*cnt[fx]-f[x]-w)/(cnt[fx]-1)+w)/(cnt[x]+1);
else d[x]+=((d[fx]*(cnt[fx]+1)-f[x]-w)/cnt[fx]+w)/(cnt[x]+1);
}
for(int i=note[x];i;i=e[i].last)
{
if(e[i].end==fx||inring[e[i].end]) continue;
dfss(e[i].end,x,e[i].weight);
}
}
void dfsss(int x,int fe)
{
if(flag) return;
vis[x]=true,ring[++tot]=x;
for(int i=note[x];i;i=e[i].last)
{
if(i==(fe^1)) continue;
if(flag) break;
if(vis[e[i].end])
{
int st=0,ed=tot,h=e[i].end;
for(int i=1;i<=tot;i++)
if(ring[i]==h) {st=i;break;}
for(int i=st;i<=ed;i++)
{
inring[ring[i]]=true;
for(int j=note[ring[i]];j;j=e[j].last)
if(e[j].end==((i==ed)?ring[st]:ring[i+1]))
{ringdis[i]=e[j].weight;break;}
}
for(int i=st;i<=ed;i++) dfs(ring[i],0);
for(int i=st;i<=ed;i++)
{
int x=ring[i];
d[x]=f[x]*cnt[x]/(cnt[x]+2);
int u=i,w=0;
double p=1;
for(;;)
{
p/=cnt[ring[u]]+((u==i)?2:1),w=ringdis[u];
u=((u+1>ed)?st:(u+1));
if(((u+1>ed)?st:(u+1))==i)
{d[x]+=p*(f[ring[u]]+w); break;}
else d[x]+=p*(f[ring[u]]*cnt[ring[u]]/(cnt[ring[u]]+1)+w);
}
u=i,w=0,p=1;
for(;;)
{
p/=cnt[ring[u]]+((u==i)?2:1),w=ringdis[(u-1<st)?ed:(u-1)];
u=((u-1<st)?ed:(u-1));
if(((u-1<st)?ed:(u-1))==i)
{d[x]+=p*(f[ring[u]]+w); break;}
else d[x]+=p*(f[ring[u]]*cnt[ring[u]]/(cnt[ring[u]]+1)+w);
}
}
for(int i=st;i<=ed;i++)
cnt[ring[i]]+=2,root=ring[i],dfss(root,0,0);
flag=true; break;
}
dfsss(e[i].end,i);
}
tot--;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int u=0,v=0,w=0;
scanf("%d%d%d",&u,&v,&w);
NewEdge(u,v,w);
NewEdge(v,u,w);
}
if(m==n-1) root=1,dfs(root,0),dfss(root,0,0);
else dfsss(1,0);
for(int i=1;i<=n;i++)
ans+=(double)1/n*d[i];
printf("%.5f",ans);
return 0;
}

Luogu P2081

Luogu P2081 [NOI2012]迷失游乐园 | 期望 DP 基环树的更多相关文章

  1. 【题解】Luogu P2081 [NOI2012]迷失游乐园

    原题传送门 这是当时冬令营课上讲的题,咕咕咕到了现在 如果这题没有环套树的话,就很套路了 需要两个数组up[i]和down[i],down[i]表示从i点第一步向下走的期望距离,up[i]表示从i点第 ...

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

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

  3. [luogu2081 NOI2012] 迷失游乐园 (树形期望dp 基环树)

    传送门 题目描述 放假了,小Z觉得呆在家里特别无聊,于是决定一个人去游乐园玩. 进入游乐园后,小Z看了看游乐园的地图,发现可以将游乐园抽象成有n个景点.m条道路的无向连通图,且该图中至多有一个环(即m ...

  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. [bzoj2878][Noi2012]迷失游乐园(基环树dp)

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

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

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

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

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

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

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

随机推荐

  1. 【PHP数据结构】图的概念和存储结构

    随着学习的深入,我们的知识也在不断的扩展丰富.树结构有没有让大家蒙圈呢?相信我,学完图以后你就会觉得二叉树简直是简单得没法说了.其实我们说所的树,也是图的一种特殊形式. 图的概念 还记得我们学习树的第 ...

  2. CSS写一个缺角的div和菱形

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  3. 手把手教你 Docker搭建nacos单机版

    Docker搭建nacos单机版步骤 一.使用 docker pull nacos/nacos-server 拉取nacos镜像 我这里没有指定版本所以是拉取latest,你也可以使用 docker ...

  4. 直接取PHP二维数组里面的值

    具体是这样的,如下一个二维数组,是从库中读取出来的. $user = array( 0 => array( 'id'    => 1, 'name'  => '张三', 'email ...

  5. css 常用语法

    1.禁止某个元素内的任何选中操作: .classname{ -webkit-user-select: none; -moz-user-select: none; -ms-user-select: no ...

  6. c++ 的学习 第3集-默认参数

    1.默认参数的意思就是  予以形参默认值 2. C++允许函数设置默认参数,在调用时可以根据情况省略实参.规则如下: 默认参数只能按照右到左的顺序 如果函数同时有声明.实现,默认参数只能放在函数声 ...

  7. Dockerfile 的常用参数注解和范例

    一. docker hello world 1.1 Dockerfile FROM centos:7.5.1804 MAINTAINER 11@qq.com CMD echo "hello ...

  8. 每个男孩的机械梦「GitHub 热点速览 v.21.41」

    作者:HelloGitHub-小鱼干 机械臂可能在医疗剧中看过,可以用来执行一些精细化的操作,例如:缝合之类的.但这次 Dummy-Robot 让你不仅看看而已,还具备一定的实操性(有一定的动手.经济 ...

  9. WEB 标准以及 W3C 的理解与认识

    01.  WEB标准 ①  web标准 简单来说可以分为结构.表现和行为. ②  结构:主要是有HTML标签组成(通俗点说,在页面body里面我们写入的标签都是为了页面的结构)   表现:即指css样 ...

  10. 初探JavaScript PDF blob转换为Word docx方法

    PDF转WORD为什么是历史难题 PDF 转Word 是一个非常非常普遍的需求,可谓人人忌危,为什么如此普遍的需求,却如此难行呢,还得看为什么会有这样的一个需求: PDF文档遵循iOS32000的规范 ...