【BZOJ】【2878】【NOI2012】迷失游乐园

树形+基环树DP/数学期望



  然而我并不会做……

  题解戳这里:http://blog.csdn.net/u011265346/article/details/46328543

  好吧先考虑一个简单点的,当m=n-1时,整个是一个树形的结构,无根树我们一般还是转成有根树来处理……然后既然是无法回头的,那么我们可以定一下方向:向下或者向上(废话)

  定义一下:

  son[x]为x的儿子的数量

  down[x]表示从x这个点出发,向叶子们走的期望长度。

  怎么算呢?其实就是所有可能的情况(所有的儿子)加起来,再求个平均,所以我们有$$down[x]=\frac{\sum (down[y]+len(x->y))}{son[x]}$$

  up[x]表示从x这个点出发,经过父亲,走到某个叶子的期望长度。

  这个看上去好难算啊……怎么算呢?我们先算出来每个结点的down[x],然后从上往下DP,这里我们需要考虑的是x的父亲 f ,我们从x向上走到他父亲 f 后(len(x->f)),可以向 f 其他的儿子走,这种方案的期望长度之和为$$ son[f]*down[f]-down[x]-len(f->x) $$如果是继续向上,这种方案的期望长度为$up[f]$,所以有$$up[x]=len(x->f) + \frac{ son[f]*down[f]-down[x]-len(f->x) + up[f]}{son[f]-1+1}$$这里son[f]-1表示是向其他儿子走,+1表示的是继续向上,这么多种方案的概率是相等的。

  那么答案怎么算?当然是$$ans=\sum_{i=1}^n \frac{down[i]*son[i]+up[i]}{son[i]+1} $$

  好的到这里我们就解决了树上的问题,那么环套树其实就是需要特殊处理一下 环上的结点以及与环直接相连的结点,怎么做呢?

  肯定是要先找环的啦= =那么我们dfs搞搞找出环上所有结点,题目限制这样的结点不多,就20个= =

  有一个东西是跟树的情况一样的,那就是从环上某个结点直接向与它相连的外向树上走的期望长度,也就是所有的down[cir[i]],这里cir[i]表示环上的点。

  算出down[cir[i]]以后,跟据刚刚的经验,我们就可以用down来算up啦!同样是从上往下算up的值,只不过这里的“树根”变成了一个环,环上的点的up值其实就是沿着环走到其他的任意一个环上的点,然后再向下走的期望长度啦,举个例子吧:(其实这一段看代码比较好……)

  环上的点编号为1、2、3、4、5,那么对于1来说,顺时针走的话,走到2的概率为1,走到3的概率为$\frac{1}{son[2]+1}$,走到4的话就再乘$\frac{1}{son[3]+1}$……逆时针走的话同理。

  同时我们沿着环每走到一个位置就加上从这里向外向树走的期望长度(注意绕一圈走到头的地方与之前的不一样,因为出发点不可能经过两次)。

  表达式比较难写……好吧其实是我懒,而且长得并不好看,还是看代码比较好:

 1 F(i,1,tot){
 2     int x=cir[i];
 3     double k=1;
 4     for(int j=nex[x];j!=x;j=nex[j]){
 5         if (nex[j]!=x)
 6             up[x]+=k*(len[hash[pre[j]]][hash[j]]+down[j]*son[j]/(son[j]+1));
 7         else
 8             up[x]+=k*(len[hash[pre[j]]][hash[j]]+down[j]);
 9         k/=(son[j]+1);
10     }
11     k=1;
12     for(int j=pre[x];j!=x;j=pre[j]){
13         if (pre[j]!=x)
14             up[x]+=k*(len[hash[nex[j]]][hash[j]]+down[j]*son[j]/(son[j]+1));
15         else
16             up[x]+=k*(len[hash[nex[j]]][hash[j]]+down[j]);
17         k/=(son[j]+1);
18     }
19     up[x]/=2;
20 }

  算出所有环上的点的up[i]以后,外向树的up[i]就跟树上情况一样了……不过由于环上的点的父节点相当于是有两个,所以这里重新定义一个fa[i],表示 i 的父亲结点的数量。那么有$$up[x]=len(x->f) + \frac{ son[f]*down[f]-down[x]-len(f->x) + up[f]*fa[f] }{son[f]-1+fa[f]}$$

另外,对于上面的所有公式,要小心分母可能为0的情况。

  1 /**************************************************************
  2     Problem: 2878
  3     User: Tunix
  4     Language: C++
  5     Result: Accepted
  6     Time:556 ms
  7     Memory:9876 kb
  8 ****************************************************************/
  9
 10 //BZOJ 2878
 11 #include<vector>
 12 #include<cstdio>
 13 #include<cstring>
 14 #include<cstdlib>
 15 #include<iostream>
 16 #include<algorithm>
 17 #define rep(i,n) for(int i=0;i<n;++i)
 18 #define F(i,j,n) for(int i=j;i<=n;++i)
 19 #define D(i,j,n) for(int i=j;i>=n;--i)
 20 #define pb push_back
 21 using namespace std;
 22 inline int getint(){
 23     int v=0,sign=1; char ch=getchar();
 24     while(ch<‘0‘||ch>‘9‘){ if (ch==‘-‘) sign=-1; ch=getchar();}
 25     while(ch>=‘0‘&&ch<=‘9‘){ v=v*10+ch-‘0‘; ch=getchar();}
 26     return v*sign;
 27 }
 28 const int N=1e5+10,INF=~0u>>2;
 29 typedef long long LL;
 30 /******************tamplate*********************/
 31 int to[N<<1],nxt[N<<1],head[N],cnt;
 32 double l[N<<1];
 33 void ins(int x,int y,double z){
 34     to[++cnt]=y; nxt[cnt]=head[x]; head[x]=cnt; l[cnt]=z;
 35 }
 36
 37 int n,m;
 38
 39 int vis[N],flag;
 40 double son[N],fa[N],up[N],down[N];
 41 int cir[N],tot,hash[N];
 42 int pre[N],nex[N];
 43 double len[25][25];
 44
 45 void Findcir(int x,int f){
 46     vis[x]=1;
 47     for(int i=head[x];i;i=nxt[i])
 48         if (to[i]!=f){
 49             if (vis[to[i]]){
 50                 flag=to[i];
 51                 return;
 52             }
 53             Findcir(to[i],x);
 54             if (flag>0){
 55                 if (flag==x) flag=-1;
 56                 return;
 57             }
 58             if (flag==-1) break;
 59         }
 60     vis[x]=0;
 61 }
 62 void dfs_cir(int x,int f){
 63     if (hash[x]) return;
 64     cir[++tot]=x;
 65     hash[x]=tot;
 66     fa[x]=2;
 67     for(int i=head[x];i;i=nxt[i]){
 68         if (to[i]==f) continue;
 69         if (!vis[to[i]]) continue;
 70
 71         pre[to[i]]=x;
 72         nex[x]=to[i];
 73         dfs_cir(to[i],x);
 74         len[hash[x]][hash[to[i]]]=len[hash[to[i]]][hash[x]]=l[i];
 75         break;
 76     }
 77 }
 78
 79 void dfsdown(int x,int f){
 80     for(int i=head[x];i;i=nxt[i])
 81         if (!vis[to[i]] && to[i]!=f){
 82             fa[to[i]]=1;
 83             dfsdown(to[i],x);
 84             son[x]++;
 85             down[x]+=down[to[i]]+l[i];
 86         }
 87     if (son[x]) down[x]/=son[x];
 88 }
 89
 90 void dfsup(int x,int f,double ee){
 91     up[x]=ee;
 92     if (fa[f]+son[f]>1)
 93         up[x]+=(fa[f]*up[f]+son[f]*down[f]-down[x]-ee)/(fa[f]+son[f]-1);
 94     for(int i=head[x];i;i=nxt[i])
 95         if (to[i]!=f) dfsup(to[i],x,l[i]);
 96 }
 97
 98 int main(){
 99 #ifndef ONLINE_JUDGE
100     freopen("2878.in","r",stdin);
101     freopen("2878.out","w",stdout);
102 #endif
103     n=getint(); m=getint();
104     F(i,1,m){
105         int x=getint(),y=getint(),z=getint();
106         ins(x,y,z); ins(y,x,z);
107     }
108     Findcir(1,0);
109     if (m<n){
110         dfsdown(1,0);
111         for(int i=head[1];i;i=nxt[i])
112             dfsup(to[i],1,l[i]);
113     }else{
114         F(i,1,n)
115             if (vis[i]){
116                 dfs_cir(i,0);
117                 break;
118             }
119         F(i,1,tot) dfsdown(cir[i],0);
120         F(i,1,tot){
121             int x=cir[i];
122             double k=1;
123             for(int j=nex[x];j!=x;j=nex[j]){
124                 if (nex[j]!=x)
125                     up[x]+=k*(len[hash[pre[j]]][hash[j]]+down[j]*son[j]/(son[j]+1));
126                 else
127                     up[x]+=k*(len[hash[pre[j]]][hash[j]]+down[j]);
128                 k/=(son[j]+1);
129             }
130             k=1;
131             for(int j=pre[x];j!=x;j=pre[j]){
132                 if (pre[j]!=x)
133                     up[x]+=k*(len[hash[nex[j]]][hash[j]]+down[j]*son[j]/(son[j]+1));
134                 else
135                     up[x]+=k*(len[hash[nex[j]]][hash[j]]+down[j]);
136                 k/=(son[j]+1);
137
138             }
139             up[x]/=2;
140         }
141         F(j,1,tot){
142             for(int i=head[cir[j]];i;i=nxt[i])
143                 if (!hash[to[i]]) dfsup(to[i],cir[j],l[i]);
144         }
145     }
146     double ans=0;
147     F(i,1,n) ans+=(up[i]*fa[i]+down[i]*son[i])/(fa[i]+son[i]);
148     printf("%.5lf\n",ans/n);
149     return 0;
150 }

2878: [Noi2012]迷失游乐园

Time Limit: 10 Sec  Memory Limit: 512 MBSec  Special Judge
Submit: 503  Solved: 321
[Submit][Status][Discuss]

Description


假了,小Z觉得呆在家里特别无聊,于是决定一个人去游乐园玩。进入游乐园后,小Z看了看游乐园的地图,发现可以将游乐园抽象成有n个景点、m条道路的无向
连通图,且该图中至多有一个环(即m只可能等于n或者n-1)。小Z现在所在的大门也正好是一个景点。小Z不知道什么好玩,于是他决定,从当前位置出发,
每次随机去一个和当前景点有道路相连的景点,并且同一个景点不去两次(包括起始景点)。贪玩的小Z会一直游玩,直到当前景点的相邻景点都已经访问过为止。
小Z所有经过的景点按顺序构成一条非重复路径,他想知道这条路径的期望长度是多少?小Z把游乐园的抽象地图画下来带回了家,可是忘了标哪个点是大门,他只
好假设每个景点都可能是大门(即每个景点作为起始点的概率是一样的)。同时,他每次在选择下一个景点时会等概率地随机选择一个还没去过的相邻景点。

Input

第一行是两个整数n和m,分别表示景点数和道路数。 接下来行,每行三个整数Xi, Yi, Wi,分别表示第i条路径的两个景点为Xi, Yi,路径长Wi。所有景点的编号从1至n,两个景点之间至多只有一条道路。

Output

共一行,包含一个实数,即路径的期望长度。

Sample Input

4 3
1 2 3
2 3 1
3 4 4

Sample Output

6.00000000

【样例解释】样例数据中共有6条不同的路径: 路径 长度 概率
1-->4 8 1/4
2-->1 3 1/8
2-->4 5 1/8
3-->1 4 1/8
3-->4 4 1/8
4-->1 8 1/4
因此期望长度 = 8/4 + 3/8 + 5/8 + 4/8 + 4/8 + 8/4 = 6.00
【评分方法】本题没有部分分,你程序的输出只有和标准答案的差距不超过0.01时,才能获得该测试点的满分,否则不得分。
【数据规模和约定】对于100%的数据,1 <= Wi <= 100。 测试点编号 n m 备注
1 n=10 m = n-1 保证图是链状
2 n=100 只有节点1的度数大于2
3 n=1000 /
4 n=100000 /
5 n=100000 /
6 n=10 m = n /
7 n=100 环中节点个数<=5
8 n=1000 环中节点个数<=10
9 n=100000 环中节点个数<=15
10 n=100000 环中节点个数<=20

HINT

Source

鸣谢Ljcc提供SPJ

[Submit][Status][Discuss]

时间: 2024-10-13 02:30:58

【BZOJ】【2878】【NOI2012】迷失游乐园的相关文章

BZOJ 2878([Noi2012]迷失游乐园-树形DP+环加外向树+期望DP+vector的erase)

2878: [Noi2012]迷失游乐园 Time Limit: 10 Sec  Memory Limit: 512 MBSec  Special Judge Submit: 319  Solved: 223 [Submit][Status] Description 放假了,小Z觉得呆在家里特别无聊,于是决定一个人去游乐园玩.进入游乐园后,小Z看了看游乐园的地图,发现可以将游乐园抽象成有n个景点.m条道路的无向连通图,且该图中至多有一个环(即m只可能等于n或者n-1).小Z现在所在的大门也正好是

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

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

BZOJ 2878: [Noi2012]迷失游乐园

Writing now. 1 /************************************************************** 2 Problem: 2878 3 User: zrts 4 Language: C++ 5 Result: Accepted 6 Time:588 ms 7 Memory:10748 kb 8 ****************************************************************/ 9 10 #i

BZOJ 2878 [Noi2012]迷失游乐园 树形期望DP+基环树

题意:链接 方法:树形期望DP+基环树 解析: 首先先看前50%的数据 是一棵树 那么我们可以搞树形DP 然后设几个正常的数组 sum[i]代表i走i的子节点的期望的和. down[i]代表从底下走到i的期望. size[i]代表i的儿子个数 up[i]代表从i往上走的期望 然后就可以推式子了 显而易见地可以推出来up的式子 然后有一些奇怪的关于根节点的特判,注意一下就OK了. 然后后50% 我们发现它是一个基环树? 那么首先可以乱搞出来环上的点,然后记录一下这个环上的点的连接方式,求一下相邻两

【BZOJ 2878】 [Noi2012]迷失游乐园

2878: [Noi2012]迷失游乐园 Time Limit: 10 Sec  Memory Limit: 512 MBSec  Special Judge Submit: 415  Solved: 283 [Submit][Status] Description 放假了,小Z觉得呆在家里特别无聊,于是决定一个人去游乐园玩.进入游乐园后,小Z看了看游乐园的地图,发现可以将游乐园抽象成有n个景点.m条道路的无向连通图,且该图中至多有一个环(即m只可能等于n或者n-1).小Z现在所在的大门也正好是

BZOJ 2878([Noi2012]-失落的游乐园树DP+出站年轮加+后市展望DP+vector的erase)

2878: [Noi2012]迷失乐园 Time Limit: 10 Sec  Memory Limit: 512 MBSec  Special Judge Submit: 319  Solved: 223 [Submit][Status] Description 放假了,小Z认为呆在家里特别无聊,于是决定一个人去游乐园玩.进入游乐园后,小Z看了看游乐园的地图,发现能够将游乐园抽象成有n个景点.m条道路的无向连通图,且该图中至多有一个环(即m仅仅可能等于n或者n-1). 小Z如今所在的大门也正好

NOI2012 迷失游乐园

http://www.lydsy.com/JudgeOnline/problem.php?id=2878 比较容易的概率题. Case1~5: 这是一棵树. 我们求出每个点i度数du[i],只走子树的期望距离g[i]和不走子树的期望距离f[i],这比较好求. 然后累加即可. Case6~10: 图中有一个环,然后环上的点都是一棵树的根. 对于每棵树,我们同样求出每个点i度数du[i],只走子树的期望距离g[i]. 那么怎么求不走子树的期望距离f[i]呢? 我们先求环上的点的f[i]吧. 我们枚举

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

Description 放假了,小Z认为呆在家里特别无聊.于是决定一个人去游乐园玩. 进入游乐园后.小Z看了看游乐园的地图,发现能够将游乐园抽象成有n个景点.m条道路的无向连通图,且该图中至多有一个环(即m仅仅可能等于n或者n-1).小Z如今所在的大门也正好是一个景点. 小Z不知道什么好玩,于是他决定,从当前位置出发,每次随机去一个和当前景点有道路相连的景点,而且同一个景点不去两次(包括起始景点).贪玩的小Z会一直游玩.直到当前景点的相邻景点都已经訪问过为止.小Z全部经过的景点按顺序构成一条非反

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

bzoj luogu 题意:一颗数或是基环树,随机从某个点开始一直走,不走已经到过的点,求无路可走时的路径长期望. 对于一棵树: 用两个$dp$数组分别记录从这个点起向上向下走的期望 向下走的$dp$不用多说 向上走的$dp$: 对于从$u$计算$v$的dp $dp[v]$应当是从u向周围引出所有路径减去走向t的路径的期望后再除以$deg_{u}-1$ 对于基环树: 环上的点很少. 此时环上的点的向上$dp$指从u出发向环上两头走的期望. 如何计算:对于环上每一个点都向环的两头各dp一次取平均值