zoukankan      html  css  js  c++  java
  • CF123E Maze(期望dp,树形dp,式子)

    题目大意:
    给你一棵树,边权都是1,每一个点有一个是起点的概率和一个是终点的概率,你将以起点为根,开始在树上随机dfs,每到一个点,就会将他的所有儿子随机打乱成序列,然后按照那个随机顺序走完,直到走到终点。求dfs从起点到终点的期望长度。

    其实一开始看到这个题,还是有点懵逼的啊

    根据期望的线性性,我们可以通过求所有相邻点的期望,然后直接相加,得到ans

    那我们可以这么考虑,对于一个点来说,假设我们要求的是从(x->y)(y)(x)的儿子)的期望的话,如果走到一个错的儿子,那么就需要(2*size[son])步重新回来(相当于每条边会走两遍),而每个儿子在对应的(y)之前的概率又都是(frac{1}{2})(所有排列中,要不是y在前,就是那一个在前)

    所以可以得知,每一个点的贡献 就是(size[x])

    那么我们可以通过枚举终点,然后算其他子树的(size[x])以及概率和,求出来他们的贡献

    最后直接输出ans就好

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<map>
    #include<set>
    #define mk makr_pair
    #define ll long long
    
    using namespace std;
    
    inline int read()
    {
      int x=0,f=1;char ch=getchar();
      while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
      while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
      return x*f;
    }
    
    const int maxn = 2e5+1e2;
    const int maxm = 2*maxn;
    
    int point[maxn],nxt[maxm],to[maxm];
    double val[maxn];
    int size[maxn];
    double st[maxn],ed[maxn];
    int n,m;
    double sumst,sumed;
    int cnt;
    double ans;
    
    void addedge(int x,int y)
    {
    	nxt[++cnt]=point[x];
    	to[cnt]=y;
    	point[x]=cnt;
    }
    
    void dfs(int x,int fa)
    {
    	size[x]=1;
    	val[x]=st[x];
    	//cout<<x<<" "<<val[x]<<endl;
    	for (int i=point[x];i;i=nxt[i])
    	{
    	   int p = to[i];
    	   if (p==fa) continue;
    	   dfs(p,x);
    	   size[x]+=size[p];
    	   val[x]+=val[p];
    	}
    } 
    int main()
    {
      n=read();
      for (int i=1;i<n;i++)
      {
      	int x=read(),y=read();
      	addedge(x,y);
      	addedge(y,x);
      }
      
      for (int i=1;i<=n;i++)
      {
      	 scanf("%lf%lf",&st[i],&ed[i]);
      	 sumst+=st[i];
      	 sumed+=ed[i];
      }
      
      for(int i=1;i<=n;i++)
      {
      	  st[i]=st[i]/sumst;
      	  ed[i]=ed[i]/sumed;
      	 // printf("%.4lf %.4lf
    ",st[i],ed[i]);
      }
      
      dfs(1,0);
      //cout<<val[1]<<endl;
      for (int x=1;x<=n;x++)
      {
      	 for  (int i=point[x];i;i=nxt[i])
      	 {
      	 	int p =to[i];
      	 	if (size[p]>=size[x])
      	 	  ans=ans+1.0*(1.0-val[x])*1.0*(1.0*n-size[x])*ed[x];
    		else
    		  ans=ans+val[p]*1.0*size[p]*ed[x];
    		  
    	//	cout<<x<<" "<<p<<" "<<ans<<endl; 
    	 }
      } 
      
      printf("%.12lf",ans);
      return 0;
    }
    
    
  • 相关阅读:
    进程和线程的主要区别
    Mysql 指定字段数据排序 以及django的实现
    java String
    阿里云 邮件发送(Python)
    Python实现类似JavaScript 的Json对象
    JAVA 学习笔记
    记录一个MySql 分区表+Gap锁引起插入超时的案例
    ThreadPoolExecutor源码中的适配器模式
    Oracle 查询真实执行计划
    简单分析FactoryBean
  • 原文地址:https://www.cnblogs.com/yimmortal/p/10161463.html
Copyright © 2011-2022 走看看