zoukankan      html  css  js  c++  java
  • Codeforces 123 E Maze

    Discription

    A maze is represented by a tree (an undirected graph, where exactly one way exists between each pair of vertices). In the maze the entrance vertex and the exit vertex are chosen with some probability. The exit from the maze is sought by Deep First Search. If there are several possible ways to move, the move is chosen equiprobably. Consider the following pseudo-code:


    DFS(x)
    if x == exit vertex then
    finish search
    flag[x] <- TRUE
    random shuffle the vertices' order in V(x) // here all permutations have equal probability to be chosen
    for i <- 1 to length[V] do
    if flag[V[i]] = FALSE then
    count++;
    DFS(y);
    count++;

    V(x) is the list vertices adjacent to x. The flag array is initially filled as FALSE. DFS initially starts with a parameter of an entrance vertex. When the search is finished, variable count will contain the number of moves.

    Your task is to count the mathematical expectation of the number of moves one has to do to exit the maze.

    Input

    The first line determines the number of vertices in the graph n (1 ≤ n ≤ 105). The next n - 1 lines contain pairs of integers ai and bi, which show the existence of an edge between ai and bi vertices (1 ≤ ai, bi ≤ n). It is guaranteed that the given graph is a tree.

    Next n lines contain pairs of non-negative numbers xi and yi, which represent the probability of choosing the i-th vertex as an entrance and exit correspondingly. The probabilities to choose vertex i as an entrance and an exit equal  and  correspondingly. The sum of all xi and the sum of all yi are positive and do not exceed 106.

    Output

    Print the expectation of the number of moves. The absolute or relative error should not exceed 10 - 9.

    Example

    Input
    2
    1 2
    0 1
    1 0
    Output
    1.00000000000000000000
    Input
    3
    1 2
    1 3
    1 0
    0 2
    0 3
    Output
    2.00000000000000000000
    Input
    7
    1 2
    1 3
    2 4
    2 5
    3 6
    3 7
    1 1
    1 1
    1 1
    1 1
    1 1
    1 1
    1 1
    Output
    4.04081632653

    Note

    In the first sample the entrance vertex is always 1 and the exit vertex is always 2.

    In the second sample the entrance vertex is always 1 and the exit vertex with the probability of 2/5 will be 2 of with the probability if 3/5 will be 3. The mathematical expectations for the exit vertices 2 and 3 will be equal (symmetrical cases). During the first move one can go to the exit vertex with the probability of 0.5 or to go to a vertex that's not the exit vertex with the probability of 0.5. In the first case the number of moves equals 1, in the second one it equals 3. The total mathematical expectation is counted as 2 / 5 × (1 × 0.5 + 3 × 0.5) + 3 / 5 × (1 × 0.5 + 3 × 0.5)

        我们如果把终点T当成树根的话,那么再把S当作起点,路径长度的期望就是 树根T包含S那个儿子的子树大小。

        为什么呢?

    1.考虑如果一条边在S到T的路径上的话,那么是肯定要经过的,期望就是1;

    2.如果一条边不在T到S的路径上,但却在T包含S那个子树里,那么它只有两种可能:被经过2次或者不经过。然后我们再强行带一波数,可以发现两者的概率是相等的(就是我们假设S和边上端点的LCA有p个儿子,那么走包含S那个子树的概率就是 1/p + (p-2)/p * 1/(p-1) +....  = 1/2)

        而这两种边数之和(子树中所有边+T到那个儿子的边)正好就是T包含S那个子树的大小,所以我们直接DFS一遍,统计每个点作为终点(树根)的答案即可。

    #include<bits/stdc++.h>
    #define ll long long
    const int maxn=100005;
    #define D double
    using namespace std;
    int n,m,hd[maxn],to[maxn*2],ne[maxn*2],siz[maxn];
    D per[maxn],ANS=0,S,T,s[maxn],t[maxn];
    
    void dfs(int x,int fa){
    	siz[x]=1;
    	for(int i=hd[x];i;i=ne[i]) if(to[i]!=fa){
    		dfs(to[i],x);
    		siz[x]+=siz[to[i]];
    		s[x]+=s[to[i]];
    		ANS+=t[x]*s[to[i]]*siz[to[i]];
    	}
    	ANS+=t[x]*(S-s[x])*(n-siz[x]);
    }
    
    int main(){
    	scanf("%d",&n);
    	int uu,vv;
    	for(int i=1;i<n;i++){
    		scanf("%d%d",&uu,&vv);
    		to[i]=vv,ne[i]=hd[uu],hd[uu]=i;
    		to[i+n]=uu,ne[i+n]=hd[vv],hd[vv]=i+n;
    	}
    	
    	for(int i=1;i<=n;i++){
    		scanf("%lf%lf",s+i,t+i);
    		S+=s[i],T+=t[i];
    	}
    	
    	dfs(1,1);
    	
    	printf("%.20lf
    ",ANS/S/T);
    	return 0;
    }
    

      

  • 相关阅读:
    Android常用开发工具的用法
    搭建Android开发环境
    开篇 Android系统的体系结构
    学习安卓笔记
    C# DllImport用法和路径问题
    jq 实现无限级地区联动 样式为bootstrap
    YII2 日志
    centos6.5 lamp 环境 使用yum安装方法
    mysql 时间戳 按周、日、月 统计方法 附 date格式
    Yii2.0中文开发向导——控制器(Controller)
  • 原文地址:https://www.cnblogs.com/JYYHH/p/8601980.html
Copyright © 2011-2022 走看看