BZOJ 2878 [Noi2012]迷失游乐园 树形期望DP+基环树
2015-08-06 17:04
363 查看
题意:链接
方法:树形期望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\frac{1}{size[1]+1}
从第二个走向第三个的概率也有,所以需要乘一下。
之后就弄完了~不过还是有很多特判
尤其是我的对于前后50%的第二个搜索不一样。。。
也懒得归一了=-=
代码:
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define N 100010 using namespace std; int n,m,cnt,tot; struct node { int from,to,val,next; }edge[N<<1]; int head ; int size ; int fa ; int cntfa ; int v ; int inc ; int cir ; int pre ; int nex ; double sum ; double up ; double dis ; double down ; 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); } }
相关文章推荐
- 在设置代理的环境下使用SharePoint CSOM
- [Jobdu] 题目1520:树的子结构
- 适配器模式的应用
- Activity被回收导致fragment的getActivity为空
- 文件的存取
- CF 567B(Berland National Library-看成折线图)
- Android 自定义View (一)
- SecureCRT上传、下载文件命令sz与rz用法实例
- Android Http请求框架二:xUtils 框架网络请求
- 随机数----srand,rand
- Extjs4 grid 鼠标响应事件
- JUnit4概述
- 消息分发机制。
- 百度地图 Fragment之间切换黑屏现象解决方案
- GraphX 实现K-Core
- Max Sum
- STL中 map的用法
- HDU 4229 Vive la Difference!
- 其他主机连接本地主机Tomcat会出现的防火墙问题
- 在Eclipse中使用JUnit4进行单元测试(高级篇)