BZOJ 2878 [Noi2012]迷失游乐园 树形期望DP+基环树
来源:互联网 发布:win10怎么ping网络 编辑:程序博客网 时间:2024/05/17 06:37
题意:链接
方法:树形期望DP+基环树
解析:
首先先看前50%的数据
是一棵树
那么我们可以搞树形DP
然后设几个正常的数组
sum[i]代表i走i的子节点的期望的和。
down[i]代表从底下走到i的期望。
size[i]代表i的儿子个数
up[i]代表从i往上走的期望
然后就可以推式子了
显而易见地可以推出来up的式子
然后有一些奇怪的关于根节点的特判,注意一下就OK了。
然后后50%
我们发现它是一个基环树?
那么首先可以乱搞出来环上的点,然后记录一下这个环上的点的连接方式,求一下相邻两点的距离什么的。
之后呢?
对于每一个环上的点,扫一遍以它为根,不走环的树形DP,同前50%,能扫出其对应子树的那些值。
之后就是更新up了
对于环上的点,我们可以是逆时针走可以是顺时针走,所以先求逆时针,后求顺时针,除个2就行。
但是怎么求呢?
来枚举这个过程。
先从环上一个点,朝逆时针方向走。
找到一个点后,用那个点的down值以及二者的距离更新我们选取的点的up值。
然后别忘了算算一下概率
不妨假设顺序为1 2 3
那我们枚举到1时
走第二个节点的概率是1size[1]+1
从第二个走向第三个的概率也有,所以需要乘一下。
之后就弄完了~不过还是有很多特判
尤其是我的对于前后50%的第二个搜索不一样。。。
也懒得归一了=-=
代码:
#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define N 100010using namespace std;int n,m,cnt,tot;struct node{ int from,to,val,next;}edge[N<<1];int head[N];int size[N];int fa[N];int cntfa[N];int v[N];int inc[N];int cir[N];int pre[N];int nex[N];double sum[N];double up[N];double dis[N];double down[N];void init(){ memset(head,-1,sizeof(head)); cnt=1;}void edgeadd(int from,int to,int val){ edge[cnt].from=from,edge[cnt].to=to,edge[cnt].val=val; edge[cnt].next=head[from]; head[from]=cnt++;}int flag;void getcir(int now,int ff){ fa[now]=ff; v[now]=1; for(int i=head[now];i!=-1;i=edge[i].next) { if(flag)return; int to=edge[i].to; if(to==ff)continue; if(v[to]!=0) { cir[++tot]=to; inc[to]=tot; cntfa[to]=2; int tmp=now; do { cir[++tot]=tmp; cntfa[tmp]=2; inc[tmp]=tot; tmp=fa[tmp]; }while(tmp!=to); flag=1;return ; }else { getcir(to,now); } }}double map[25][25];int ccccnt;void dfscir(int now,int fa){ for(int i=head[now];i!=-1;i=edge[i].next) { int to=edge[i].to; if(!inc[to]||to==fa||ccccnt==tot)continue; ccccnt++; pre[to]=now; nex[now]=to; dfscir(to,now); map[inc[to]][inc[now]]=map[inc[now]][inc[to]]=(double)edge[i].val; break; }}void dfs(int now,int fa){ for(int i=head[now];i!=-1;i=edge[i].next) { int to=edge[i].to; if(to==fa||inc[to])continue; cntfa[to]=1; dfs(to,now); dis[to]=edge[i].val; size[now]++; sum[now]+=down[to]+edge[i].val; } if(size[now]!=0)down[now]=sum[now]/(double)size[now];}void dfs3(int now,int fa,int root){ if(now!=1) { double tmp=sum[fa]-dis[now]+up[fa]; if(size[now]!=0)tmp-=sum[now]/size[now]; if(fa==1)up[now]=tmp/(size[fa]-1); else up[now]=tmp/size[fa]; up[now]+=dis[now]; } for(int i=head[now];i!=-1;i=edge[i].next) { int to=edge[i].to; if(to==fa)continue; dfs3(to,now,root); }}void dfs2(int now,int fa,int root){ if(now!=root) { double tmp=sum[fa]-dis[now]+up[fa]; if(inc[fa])tmp+=up[fa]; if(size[now]!=0)tmp-=sum[now]/size[now]; if(inc[fa])up[now]=tmp/(size[fa]+1); else up[now]=tmp/size[fa]; up[now]+=dis[now]; } for(int i=head[now];i!=-1;i=edge[i].next) { int to=edge[i].to; if(to==fa)continue; dfs2(to,now,root); }}double ans;int main(){ init(); scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) { int x,y,z; scanf("%d%d%d",&x,&y,&z); edgeadd(x,y,z); edgeadd(y,x,z); } if(m==n-1) { dfs(1,-1); dfs3(1,-1,1); for(int i=1;i<=n;i++) { if(i==1)ans+=(sum[i]+up[i])/(double)(size[i]); else ans+=(sum[i]+up[i])/(double)(size[i]+1); } ans/=(double)n; printf("%.5lf\n",ans); }else { getcir(1,-1); dfscir(cir[1],-1); for(int i=1;i<=n;i++)if(inc[i])dfs(i,-1); for(int i=1;i<=tot;i++) { double k=1; int now=cir[i]; for(int j=nex[now];j!=now;j=nex[j]) { if(nex[j]!=now) { up[now]+=k*(map[inc[pre[j]]][inc[j]]+down[j]*size[j]/(size[j]+1)); }else { up[now]+=k*(map[inc[pre[j]]][inc[j]]+down[j]); } k/=(size[j]+1); } k=1; for(int j=pre[now];j!=now;j=pre[j]) { if(pre[j]!=now) { up[now]+=k*(map[inc[nex[j]]][inc[j]]+down[j]*size[j]/(size[j]+1)); }else { up[now]+=k*(map[inc[nex[j]]][inc[j]]+down[j]); } k/=(size[j]+1); } up[now]/=2.0; } for(int i=1;i<=tot;i++) { int now=cir[i]; for(int j=head[now];j!=-1;j=edge[j].next) { int to=edge[j].to; if(!inc[to])dfs2(to,now,now); } } double ans=0; for(int i=1;i<=n;i++) { if(inc[i]) { ans+=(up[i]*2+down[i]*size[i])/(double)(2+size[i]); }else ans+=(up[i]+down[i]*size[i])/(double)(1+size[i]); } printf("%.5lf\n",ans/(double)n); }}
0 0
- BZOJ 2878 [Noi2012]迷失游乐园 树形期望DP+基环树
- [环套树 树形DP 期望] BZOJ 2878 [Noi2012]迷失游乐园
- BZOJ 2878([Noi2012]迷失游乐园-树形DP+环加外向树+期望DP+vector的erase)
- 2878: [Noi2012]迷失游乐园 基环树+DP+概率与期望
- NOI2012 迷失游乐园 期望+树形dp+基环外向树
- 【BZOJ 2878】 [Noi2012]迷失游乐园
- BZOJ 2878 Noi2012 迷失游乐园
- 【基环树DP】[NOI2012]迷失游乐园
- [BZOJ2878][Noi2012]迷失游乐园 && 树形DP
- bzoj2878 [Noi2012]迷失游乐园 [树形dp]
- 2878: [Noi2012]迷失游乐园
- 【NOI2012T4】迷失游乐园-环套树+树形DP+期望DP
- 【bzoj2878】[Noi2012]迷失游乐园 环套树概率dp
- bzoj-2878 迷失游乐园
- [bzoj2878][NOI2012]迷失游乐园
- BZOJ2878: [Noi2012]迷失游乐园
- [NOI2012]迷失游乐园(树上递推)
- BZOJ 2827 NOI 2012 迷失游乐园 pascal
- [Erlang]系统瓶颈检测
- Struts2验证框架
- CAS+SSO原理浅谈 - 很详细
- 另一个ISIS配置-来自leaf(linux embedded a f)
- 浅谈:狄克斯特拉算法Dijkstra找最小树问题
- BZOJ 2878 [Noi2012]迷失游乐园 树形期望DP+基环树
- CF 567C(Geometric Progression-map)
- 博客集
- 刘亦菲宋承宪恋情曝光 男方认爱:刚开始交往
- CentOS Linux 5.9 32bit搭建L2TP ipsec VPN服务器
- 安卓 自定义activity(活动)切换效果
- POJ 2001 Shortest Prefixes 【 trie树(别名字典树)】
- 面试题1
- Threejs创建及设置face