题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2878

这个博客写得很好:https://www.cnblogs.com/qt666/p/7252284.html

其实就是分成子树部分(down)和向上的部分(up)来考虑、转移;

要想清楚vis的作用等等,还有那个ed的使用,是和fa配套的,也就是只在子树中使用;

期望就是其他状态的期望和除以总状态数,只要想清楚有些什么状态就很好转移了!

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int const maxn=3e5+;
int n,m,fa[maxn],f[maxn],son[maxn],head[maxn],ct,ed[maxn],cir[maxn],cnt,dfn[maxn],tim,b[maxn];
double down[maxn],up[maxn],ans;
bool vis[maxn];
struct N{
int to,next,w;
N(int t=,int n=,int w=):to(t),next(n),w(w) {}
}edge[maxn];
void add(int x,int y,int z)
{
edge[++ct]=N(y,head[x],z);head[x]=ct;
edge[++ct]=N(x,head[y],z);head[y]=ct;
}
void dfs_down(int x)
{
vis[x]=;int tot=;
for(int i=head[x],v;i;i=edge[i].next)
{
if(vis[v=edge[i].to])continue;
ed[v]=edge[i].w;//
dfs_down(v);tot++;
down[x]+=down[v]+edge[i].w;
}
if(tot)down[x]/=tot;//
son[x]=tot;vis[x]=;//
}
void dfs_up(int x,int u)
{
// fa[x]=u;f[x]=1;
// if(u&&son[u])up[x]+=(up[u]+down[u]*son[u]-down[x]-ed[x])/son[u]+ed[x];
// for(int i=head[x],v;i;i=edge[i].next)
// if(!f[v=edge[i].to])ed[v]=edge[i].w,dfs_up(v,x);
vis[x]=;if(u) f[x]=;
if((son[u]-+f[u])&&u) up[x]+=(up[u]*f[u]+son[u]*down[u]-down[x]-ed[x])/(son[u]-+f[u]);//特判根节点(只有一个son的)
for(int i=head[x],v;i;i=edge[i].next)
if(!vis[v=edge[i].to]) /*ed[i]=edge[i].w,*/
up[v]+=edge[i].w,dfs_up(v,x);//在down时已求出ed
}
void make(int rt,int x)
{
for(int i=x;i!=fa[rt];i=fa[i])//不是i!=rt !!!
cir[++cnt]=i,b[cnt+]=ed[i],f[i]=,vis[i]=;//vis在dfs_down中会用
//犯蠢把 cir[++cnt]=i 写成 cir[++cnt]=x ,调了半天!!!
}
void tarjan(int x,int ff)
{
dfn[x]=++tim;fa[x]=ff;
for(int i=head[x],v;i;i=edge[i].next)
{
if(!dfn[v=edge[i].to])ed[v]=edge[i].w,tarjan(v,x);
else if(dfn[v]>dfn[x])b[]=edge[i].w,make(x,v);
}
}
void solve(int x,int j,int step)
{
double g=0.5,d=;
for(int i=;i<cnt;i++)//所求的都是up[x]!
{
if(step==-)d+=b[j];j+=step;//是b而不是ed
if(j==)j=cnt;if(j==cnt+)j=;
if(step==)d+=b[j];//j+后再+b[j],顺、逆时针有所区分
if(i==cnt-)up[x]+=g*(d+down[cir[j]]);
else up[x]+=g*(d+down[cir[j]])*son[cir[j]]/(son[cir[j]]+);
g/=son[cir[j]]+;
}
}
void work()//!
{
tarjan(,);
for(int i=;i<=cnt;i++)dfs_down(cir[i]),vis[cir[i]]=;//
for(int i=;i<=cnt;i++)solve(cir[i],i,),solve(cir[i],i,-);
for(int i=;i<=cnt;i++)dfs_up(cir[i],);//由于vis,只处理子树
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=,x,y,z;i<=m;i++)
scanf("%d%d%d",&x,&y,&z),add(x,y,z);
if(m==n-)dfs_down(),dfs_up(,);
else work();
for(int i=;i<=n;i++)
ans+=(down[i]*son[i]+up[i]*f[i])/(son[i]+f[i]);
printf("%.5lf",ans/n);//ans/n!
return ;
}

bzoj2878 [Noi2012]迷失游乐园——概率期望DP的更多相关文章

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

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

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

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

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

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

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

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

  5. BZOJ2878 [Noi2012]迷失游乐园 【基环树 + 树形dp + 期望dp】

    题目链接 BZOJ2878 题解 除了实现起来比较长,思维难度还是挺小的 观察数据范围发现环长不超过\(20\),而我们去掉环上任何一个点就可以形成森林 于是乎我们枚举断掉的点,然后只需求出剩余每个点 ...

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

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

  7. BZOJ2878 [Noi2012]迷失游乐园

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

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

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

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

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

随机推荐

  1. Codeforces 959 D Mahmoud and Ehab and another array construction task

    Discription Mahmoud has an array a consisting of n integers. He asked Ehab to find another arrayb of ...

  2. easyui分页时,总页数出错

    错误出现 MyBatis用easyui写后台分页代码时,出现翻页后显示总页数错误 代码如下 可能原因在于后台mappers.xml里的sql语句错误 <select id="getPr ...

  3. 提高google网站访问速度

    修改:C:\Windows\System32\drivers\etc\hosts文件 # google websites.203.208.46.180 ssl.gstatic.com203.208.4 ...

  4. mysql 隔离级别与间隙锁等

    数据库隔离级 SQL标准中DB隔离级别有: read uncommitted:可以读到其它transaction 未提交数据 read committed:可以读到其它transaction 已提交数 ...

  5. argument to nsmutablearray method addobject cannot be nil 警告

    You cannot add nil to an NSMutableArray, and you will raise an exception if you try to. There's NSNu ...

  6. Cocoa开发中, 如何用全局变量

    比如在tabbar的开发中,可以某个页面的数据需要在back到此页面后依然有效. 可以用 appDelegate 这个对象来创建你的全局数据 这个内建的对象,在 APP 启动时产生,在 APP 退出时 ...

  7. [原创]安装Ubuntu Server 14.04后

    安装后许多软件都没有,需要进行安装. 官方指南:https://help.ubuntu.com/lts/serverguide/index.html 1.修改网络配置文件 用ifconfig查看本地网 ...

  8. [Cypress] install, configure, and script Cypress for JavaScript web applications -- part2

    Use Cypress to test user registration Let’s write a test to fill out our registration form. Because ...

  9. ActiveMQ(三) 转

    package pfs.y2017.m11.mq.activemq.demo03; import javax.jms.Connection; import javax.jms.ConnectionFa ...

  10. opencvSGBM半全局立体匹配算法的研究(1)

    转载请说明出处:http://blog.csdn.net/zhubaohua_bupt/article/details/51866567 这段时间对opencvSGBM半全局立体匹配算法进行了比較仔细 ...