zoukankan      html  css  js  c++  java
  • [CSP-S模拟测试]:tree(DP)

    题目传送门(内部题57)


    输入格式

    第一行包含一个数:$n$表示树的节点数。
    接下来$n-1$行,每行包含两个数:$u,v$表示无根树的一条边。


    输出格式

    输出$n$行,第$i$行包含一个浮点数,保留三位小数,表示第$i$号点第一次访问的期望时间。


    样例

    样例输入:

    3
    1 2
    2 3

    样例输出:

    1.000
    2.000
    5.000


    数据范围与提示

    样例解释:

    样例解释:容易分析出,所有可能情况下,到达$1$号点和$2$号点的时间都分别是:$1$和$2$,我们考虑$3$号点的到达时间,所有可能的过程:$12(12)*3$,表示先到$1$号店,再到$2$号点,然后重复任意次$1$、$2$(可以是$0$次),最后到达$3$。
    对于$12(12)^i3$这个具体过程来说(表示中间经过$i$次$1$、$2$),到达$3$号点的时间是$t_i=2(i+1)+1$,这个随机过程的概率是$p_i={(frac{1}{2})}^{(i+1)}$,期望的时间是$E(u=3)=sum limits_{i=0}^{infty}t_ip_i=5$,故到达$3$号点的期望时刻为$5$。

    数据范围:

    对于$10\%$的数据,$1leqslant 10$,保证每个点的度不超过$2$;
    对于另外$20\%$的数据,$1leqslant nleqslant {10}^5$,保证每个点的度不超过$2$;
    对于另外$20\%$的数据,$1leqslant nleqslant 100$;
    对于$100\%$的数据,$1leqslant nleqslant {10}^5$。


    题解

    考虑$DP$,设$dp[i]$表示到达$i$点的期望时间。

    你可能会很容易的推出来一个式子:

    $$dp[u]=dp[fa]+2(n-size[u])-1$$

    然后你会发现没有小数,删掉它交暴力。

    这就是我的考试全过程……

    然而,三位小数就是逗我玩的……

    无语……

    下面讲一下推导:

    考虑一个随机过程,第一次走到$u$号点的时间可以分成两部分,第一部分是从$1$号点随机游走第一次走到$u$的父亲$p$的时间,第二部分是从$p$开始走,第一次走到$u$的时间,由期望的线性性,第一次走到$u$的时间期望等于这两部分期望的和。第一部分是一个子问题,我们考虑怎么解决第二部分,我们把这个问题变成一棵树(并且根节点脑袋上也有一条边),从根节点开始随机游走,走出这棵树期望的时间,我们用$x_u$表示这个期望,我们对$u$的子树中的点也类似地定义$x_v$,这样我们可以列出关系式:

    $$x_u=frac{(1+sum limits_{v}(x_u+x_v+1))}{d}$$

    其中$d$是$u$的度数(包括那根天线),这个关系是中的第一个$1$表示直接向上走,后面那个扩后中的三部分,那个$1$表示从$u$走向$v$,$x_v$表示从$v$走回来期望时间, 表示这个时候继续走,走出去还需要花的时间。因为是等概率,所以直接乘以$frac{1}{d}$这个概率即可。化简后是:

    $$x_u=d+sum limits_{v}x_v$$

    即$x_u$等于$u$这棵子树的所有节点度的和,考虑到除了那根天线之外,所有的边对度的贡献为$2$,所以:

    $$x_u=2size[u]+1$$

    这样,子问题就有了一个简单的答案了。我们回到原问题,用$dp[u]$表示第一次走到$u$的期望时间,用$fa$表示$u$的父亲,有:

    $$dp[u]=dp[fa]+2(n-size[u])-1$$

    时间复杂度:$Theta(n)$。

    期望得分:$100$分。

    实际得分:$100$分。


    代码时刻

    #include<bits/stdc++.h>
    using namespace std;
    struct rec{int nxt,to;}e[200001];
    int head[100001],cnt;
    int n;
    bool vis[100001];
    int size[100001];
    long long dp[100001];
    void add(int x,int y)
    {
    	e[++cnt].nxt=head[x];
    	e[cnt].to=y;
    	head[x]=cnt;
    }
    void dfs1(int x)
    {
    	vis[x]=1;
    	size[x]=1;
    	for(int i=head[x];i;i=e[i].nxt)
    		if(!vis[e[i].to])
    		{
    			dfs1(e[i].to);
    			size[x]+=size[e[i].to];
    		}
    }
    void dfs2(int x)
    {
    	vis[x]=1;
    	for(int i=head[x];i;i=e[i].nxt)
    		if(!vis[e[i].to])
    		{
    			dp[e[i].to]=dp[x]+2*(n-size[e[i].to])-1;
    			dfs2(e[i].to);
    		}
    }
    int main()
    {
    	scanf("%d",&n);
    	for(int i=1;i<n;i++)
    	{
    		int x,y;
    		scanf("%d%d",&x,&y);
    		add(x,y);add(y,x);
    	}
    	dfs1(1);
    	memset(vis,0,sizeof(vis));
    	dp[1]=1;
    	dfs2(1);
    	for(int i=1;i<=n;i++)
    		printf("%.3lf
    ",(double)dp[i]);
    	return 0;
    }
    

    rp++

  • 相关阅读:
    Bootstrap 2.2.2 的新特性
    Apache POI 3.9 发布,性能显著提升
    SQL Relay 0.48 发布,数据库中继器
    ProjectForge 4.2.0 发布,项目管理系统
    红帽企业 Linux 发布 6.4 Beta 版本
    红薯 快速的 MySQL 本地和远程密码破解
    MariaDB 宣布成立基金会
    Percona XtraBackup 2.0.4 发布
    Rocks 6.1 发布,光盘机群解决方案
    精通Servlet研究,HttpServlet的实现追究
  • 原文地址:https://www.cnblogs.com/wzc521/p/11586404.html
Copyright © 2011-2022 走看看