题目链接

基环树套路题。(然而各种错误调了好久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. java线程day-02

    1.什么是线程 * 线程是程序执行的一条路径, 一个进程中可以包含多条线程 * 多线程并发执行可以提高程序的效率, 可以同时完成多项工作 2.多线程的应用场景 * 红蜘蛛同时共享屏幕给多个电脑 * 迅 ...

  2. 快乐中秋,SQL小白入门指南

    目录 创建表 最基本的创建 怎么查看一个已经建好的表的信息呢 修改字段 插入数据 修改和删除数据 修改 删除 第一个查询 条件语句 使用age的大小比较,查看大于16岁的学生: 使用多个条件并联,大于 ...

  3. P1074 [NOIP2009 提高组] 靶形数独

    #include<bits/stdc++.h> using namespace std; const int N=10; int a[N][N],ans[N][N],vis[3][N][N ...

  4. requests接口自动化-pytest框架

    pytest框架规则 测试文件以test_开头或者以_test结尾 测试类以Test开头,并且不能带有init方法 测试函数以test_开头 断言使用assert pytest框架运行用例 运行单个文 ...

  5. Appium调试分析方法

    在使用appium做自动化测试的时候,发现用例报错,如何排查原因? 查看appium日志 appium日志大概是分为以下部分 culr命令调试 在理解appium协议的基础上,可以直接用shell发送 ...

  6. python三种导入模块的方法

    做为python初学者,有时候搞不清楚导入模块的作用. 直接导入模块 通常模块为一个文件,直接使用import来导入就好了.可以作为module的文件类型有".py"." ...

  7. 重新嫁接rm命令

    ### 重定义rm命令 #### 定义回收站目录trash_path='~/.trash'# 判断 $trash_path 定义的文件是否存在,如果不存在,那么就创建 $trash_path.if [ ...

  8. 使用form插件 和ajax 结合使用 没有调用success的原因

    当我做文件上传的时候出现不调用success方法  将datype: 'json' 注释掉后成功响应 浏览器显示200状态码,并且响应头为json格式,格式ajax不认为它是json,所以一直执行错误 ...

  9. nginx 配置文件(支持thnkphp3.2~5)

    server { listen 8080 ; server_name localhost; set $root /var/www/myweb; #listen 443 ssl; #ssl_certif ...

  10. bzoj4025-二分图【线段树分治,并查集】

    正题 题目链接:https://darkbzoj.tk/problem/4025 题目大意 \(n\)个点\(m\)条边,每条边会在一个\(T\)以内的时间段内出现,对于任意一个\(T\)以内的时刻求 ...