• [CSP校内集训]tree(期望DP)


    题意

    给一颗树,从1节点出发,走每条边的概率相同且耗时为1,求每个点第一次被遍历到的期望时间((t_1=1)

    思路

    在树上只有两种移动方式:从儿子到父亲,从父亲到儿子

    假设从(rt)走到(v)的期望代价为(dow_i),从(i)走到(rt)的期望代价为(val_i)

    假设从(rt)转移到(v)(rt)的度数为(k)(rt)的父亲为(fa),则:

    [dow_v = frac{1}{k} + sum_{son}^{son eq v} { frac{1}{k} imes (1+val_{son}+dow_v)} + frac{1}{k} imes (1+dow_{fa}+dow_v) ]

    意思是:要么从(rt)(v)一步到位,要么有(frac{1}{k})的概率走其他点再走回来重新计算期望

    化简得:

    [dow_v = k + sum_{son}^{son eq v} {val_{son} + dow_{fa}} ]

    这里还有个(val)不知道,所以要先计算它:

    [val_{rt} = sum_{son} {frac{1}{k} + frac{1}{k} imes (1+val_{son}+val_{rt})} ]

    意思是:要么从(v)(rt)一步到位,要么走一步到儿子走回来在重新计算期望

    化简得:

    [val_{rt} = k + sum_{son} {val_{son}} ]

    一遍(dfs)自底向上求(val),再一遍(dfs)从上到下求(dow),一个点的答案即为(dow)的前缀和

    Code

    #include<bits/stdc++.h>
    #define N 100005
    #define Min(x,y) ((x)<(y)?(x):(y))
    #define Max(x,y) ((x)>(y)?(x):(y))
    using namespace std;
    int n,rd[N],ok=1;
    double val[N],dow[N],f[N];
    
    struct Edge
    {
    	int next,to;
    }edge[N<<1];int head[N],cnt=1;
    void add_edge(int from,int to)
    {
    	edge[++cnt].next=head[from];
    	edge[cnt].to=to;
    	head[from]=cnt;
    }
    
    template <class T>
    void read(T &x)
    {
    	char c; int sign=1;
    	while((c=getchar())>'9'||c<'0') if(c=='-') sign=-1; x=c-48;
    	while((c=getchar())>='0'&&c<='9') x=(x<<1)+(x<<3)+c-48; x*=sign;
    }
    void dfs1(int rt,int fa)
    {
    	val[rt]=rd[rt];
    	for(int i=head[rt];i;i=edge[i].next)
    	{
    		int v=edge[i].to;
    		if(v==fa) continue;
    		dfs1(v,rt);
    		val[rt]+=val[v];
    	}
    }
    void dfs(int rt,int fa)
    {
    	double sumval=0;
    	for(int i=head[rt];i;i=edge[i].next)
    	{
    		int v=edge[i].to;
    		if(v==fa) continue;
    		sumval+=val[v];
    	}
    	for(int i=head[rt];i;i=edge[i].next)
    	{
    		int v=edge[i].to;
    		if(v==fa) continue;
    		f[v]=f[rt]+rd[rt]+dow[rt]+sumval-val[v];
    		dow[v]=f[v]-f[rt];
    		dfs(v,rt);
    	}
    }
    void solve()
    {
    	dfs1(1,0);
    	f[1]=1.0; dow[1]=0;
    	dfs(1,0);
    	for(int i=1;i<=n;++i) printf("%.3lf
    ",f[i]);
    }
    int main()
    {
    	freopen("tree.in","r",stdin);
    	freopen("tree.out","w",stdout);
    	read(n);
    	for(int i=1;i<n;++i)
    	{
    		int x,y;
    		read(x);read(y);
    		add_edge(x,y);
    		add_edge(y,x);
    		++rd[x];++rd[y];
    	}
    	solve();
    	return 0;
    }
    
  • 相关阅读:
    构建一个真实的应用电子商务SportsStore3
    关于计算程序运行时间的方法汇总
    系统分析员备考之CMM篇
    大数据时代的技术hive:hive的数据类型和数据模型
    图片滚动图片的效果
    React初探
    所有的分页查询一览及数据导出(easyui + knouckoutjs + mvc4.0)
    golang微信公众平台之人脸识别
    测试rest接口的两个工具使用详解(restclient+soapUI)
    Linux系统服务基础
  • 原文地址:https://www.cnblogs.com/Chtholly/p/11730108.html
Copyright © 2020-2023  润新知