题目链接

基环树套路题。(然而各种错误调了好久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. 图的遍历BFS广度优先搜索

    图的遍历BFS广度优先搜索 1. 简介 BFS(Breadth First Search,广度优先搜索,又名宽度优先搜索),与深度优先算法在一个结点"死磕到底"的思维不同,广度优先 ...

  2. 剑指offer计划20( 搜索与回溯算法中等)---java

    1.1.题目1 剑指 Offer 07. 重建二叉树 1.2.解法 注释解法. 1.3.代码 class Solution { int[] preorder; HashMap<Integer, ...

  3. 【OI】WERTYU UVa 10082

    题目: A common typing error is to place the hands on the keyboard one row to the right of the correct ...

  4. CentOS Linux 简单安装 clickhouse

    本文只是仅仅的介绍安装 至于更多介绍请自信百度 1.本人 linux版本 [root@localhost /]# cat /etc/redhat-releaseCentOS Linux release ...

  5. ecshop后台设置模板的地方显示自己新建模板的操作界面

    我建立了一个叫test.dwt文件怎样在后台设置模板里面出现呢.1首先找到ecshop目录下的languages\zh_cn\admin/template.php 这个php文件 当然如果这只是简体中 ...

  6. DEDE整合套件实现本地多个网站随意切换的开发环境

    一.修改WEB全局配置: 在Listen 80 后面添加自己的端口号. 例如,2020是我的端口 Listen 2020 二.修改WEB站点配置: a---在NameVirtualHost *:80后 ...

  7. Jmeter系列(7)- 分析源码,创建下单、用户注销接口请求

    源码分析 下单 用户注销 创建请求 下单 用户注销 请求调整 将信息头管理器从[02.浏览订单]请求中抽出来就变成公用的.[03,04]请求不需要单独再加信息头管理器 DeBug取样器 添加DeBug ...

  8. Linux C语言 取得MTU (最大传输单元)

    参照这篇博客: http://www.geekpage.jp/programming/linux-network/book/04/4-21.php * 查看主机当前网卡,哪块在使用. ifconfig ...

  9. python 正则表达式findall

    re.findall("匹配规则", "要匹配的字符串") 以列表形式返回匹配到的字符串 https://www.cnblogs.com/gufengchen/ ...

  10. SpringCloud升级之路2020.0.x版-25.OpenFeign简介与使用

    本系列代码地址:https://github.com/JoJoTec/spring-cloud-parent OpenFeign 的由来和实现思路 在微服务系统中,我们经常会进行 RPC 调用.在 S ...