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

2878: [Noi2012]迷失游乐园

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.00000

【样例解释】样例数据中共有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

 

 

【分析】

  这题是长且臭类型?

  反正是个基环树。

  考虑如果是一棵树的话,就是两遍的dfs,一遍上一遍下。

  我的数组f[i]表示从i一定往下走(就是无视上去的路,’下‘指的是所在外向树的下方)的期望长度。

  g[i]表示一开始先向上走(不是基环上的点第一步就只有一种,是基环上的点就有两种)

  f[i]数组直接树形概率dp(与环无关,而且一旦向下走就不会再往上)

  g[i]数组,如果没有环的存在的话,每棵树的根节点的g值就是0,有环的话,就模拟走环(数据<=20),求出所有基环上的点的g值。

  然后dfs一遍更新外向树上点的g值。

  最后把答案更新。

  安利两个题解?

  http://blog.csdn.net/u011265346/article/details/46328543

  http://www.cnblogs.com/Tunix/p/4561493.html

 

  其实细节很多。。这题还是挺ws的。。

 

  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cstring>
  4 #include<iostream>
  5 #include<algorithm>
  6 #include<set>
  7 using namespace std;
  8 #define Maxn 100010
  9 
 10 struct node
 11 {
 12     int x,y,next,o,c;
 13     bool p;
 14 }t[Maxn*2];int len;
 15 int first[Maxn];
 16 int n,m;
 17 
 18 void ins(int x,int y,int c)
 19 {
 20     t[++len].x=x;t[len].y=y;t[len].c=c;
 21     t[len].next=first[x];first[x]=len;
 22     t[len].p=1;
 23     if(len%2==0) t[len].o=len-1;
 24     else t[len].o=len+1;
 25 }
 26 
 27 int hw[Maxn],nw[Maxn],k[Maxn];
 28 bool vis[Maxn];
 29 bool ffind(int x,int f)
 30 {
 31     vis[x]=1;
 32     for(int i=first[x];i;i=t[i].next) if(t[i].p)
 33     {
 34         t[i].p=t[t[i].o].p=0;
 35         int y=t[i].y;
 36         if(vis[y]) {hw[++hw[0]]=y;nw[hw[0]]=t[i].c;hw[++hw[0]]=x;return 1;}
 37         if(ffind(y,x)) {nw[hw[0]]=t[i].c;hw[++hw[0]]=x;return 1;}
 38     }
 39     return 0;
 40 }
 41 
 42 double f[Maxn],g[Maxn];
 43 int son[Maxn];
 44 double ans=0;
 45 void dfs(int x,int ff)
 46 {
 47     f[x]=0;
 48     int cnt=0;
 49     for(int i=first[x];i;i=t[i].next) if(vis[t[i].y]&&t[i].y!=ff)
 50         cnt++;
 51     son[x]=cnt;
 52     for(int i=first[x];i;i=t[i].next) if(vis[t[i].y]&&t[i].y!=ff)
 53     {
 54         int y=t[i].y;
 55         dfs(y,x);
 56         f[x]+=(f[y]+t[i].c)/cnt;
 57     }
 58     ans+=f[x]*cnt/k[x]/n;
 59 }
 60 
 61 void dfs2(int x,int ff)
 62 {
 63     double tot=0;
 64     for(int i=first[x];i;i=t[i].next) if(vis[t[i].y]&&t[i].y!=ff)
 65         tot+=f[t[i].y]+t[i].c;
 66     for(int i=first[x];i;i=t[i].next) if(vis[t[i].y]&&t[i].y!=ff)
 67     {
 68         int y=t[i].y;
 69         if(k[x]==1)
 70         {
 71             if(ff==0) g[y]=g[x]+t[i].c;
 72             else g[y]=g[x]+t[i].c;
 73         }
 74         else
 75         {
 76             if(g[x]) g[y]=g[x]/(k[x]-1);
 77             if(son[x]>1) g[y]+=(tot-f[y]-t[i].c)/(k[x]-1);
 78             g[y]+=t[i].c;
 79         }
 80     }
 81     for(int i=first[x];i;i=t[i].next) if(vis[t[i].y]&&t[i].y!=ff)
 82         dfs2(t[i].y,x);
 83     ans+=g[x]/k[x]/n;
 84 }
 85 
 86 int main()
 87 {
 88     scanf("%d%d",&n,&m);
 89     len=0;
 90     memset(first,0,sizeof(first));
 91     for(int i=1;i<=m;i++)
 92     {
 93         int x,y,c;
 94         scanf("%d%d%d",&x,&y,&c);
 95         ins(x,y,c);ins(y,x,c);
 96     }
 97     for(int i=1;i<=n;i++)
 98     {
 99         k[i]=0;
100         for(int j=first[i];j;j=t[j].next) k[i]++;
101     }
102     hw[0]=0;
103     memset(vis,0,sizeof(vis));
104     ffind(1,0);
105     while(hw[hw[0]]!=hw[1]) hw[0]--;hw[0]--;
106     memset(vis,1,sizeof(vis));
107     for(int i=1;i<=hw[0];i++) vis[hw[i]]=0;
108     if(n-1==m)
109     {
110         dfs(1,-1);
111         g[1]=0;
112         dfs2(1,-1);
113     }
114     else
115     {
116         nw[0]=nw[hw[0]];
117         for(int i=1;i<=hw[0];i++)
118         {
119             dfs(hw[i],0);
120         }
121         for(int i=1;i<=hw[0];i++)
122         {
123             g[hw[i]]=0;
124             double p=1;
125             int hh=0;
126             for(int j=1;j<hw[0];j++)
127             {
128                 int y=(i-1+j)%hw[0]+1;
129                 hh+=nw[y-1];
130                 y=hw[y];
131                 if(j==hw[0]-1) g[hw[i]]+=p*(f[y]+hh);
132                 else g[hw[i]]+=p*(k[y]-2)/(k[y]-1)*(f[y]+hh);
133                 p/=k[y]-1;
134             }
135             p=1;hh=0;
136             for(int j=1;j<hw[0];j++)
137             {
138                 int y=(i-1-j+hw[0])%hw[0]+1;
139                 hh+=nw[y];
140                 y=hw[y];
141                 if(j==hw[0]-1) g[hw[i]]+=p*(f[y]+hh);
142                 else g[hw[i]]+=p*(k[y]-2)/(k[y]-1)*(f[y]+hh);
143                 p/=k[y]-1;
144             }
145         }
146         for(int i=1;i<=hw[0];i++)
147         {
148             dfs2(hw[i],0);
149         }
150     }
151     
152     printf("%.5lf\n",ans);
153     return 0;
154 }
View Code

 

2017-02-11 08:40:19

posted @ 2017-02-11 08:34  konjak魔芋  阅读(253)  评论(0编辑  收藏  举报