【NOIP2016提高A组模拟7.17】寻找

44 篇文章 0 订阅
30 篇文章 0 订阅

Description

Bob和Alice出去度蜜月,但Alice不慎走失,Bob在伤心过后,决定前去寻找Alice。
他们度蜜月的地方是一棵树,共有N个节点,Bob会使用下列DFS算法对该树进行遍历。

starting_time是一个容量为n的数组
current_time = 0
dfs(v):        
       current_time = current_time + 1        
       starting_time[v] = current_time        
       将children[v]的顺序随机排列 (每个排列的概率相同)        
       // children[v]v的直接儿子组成的数组        
       for u in children[v]:               
               dfs(u)

1是这棵树的根,Bob会从1出发,即运行dfs(1),现在他想知道每个点starting_time的期望值。

Input

第一行一个数N,表示节点数
第二行N-1个数,第i个数表示节点i+1的父节点(保证parent[i]

Output

一行N个小数,第i个数表示starting_time[i]的期望值,保留一位小数。

Sample Input

输入1:
7
1 2 1 1 4 4
输入2:
12
1 1 2 2 4 4 3 3 1 10 8

Sample Output

输出1:
1.0 4.0 5.0 3.5 4.5 5.0 5.0
输出2:
1.0 5.0 5.5 6.5 7.5 8.0 8.0 7.0 7.5 6.5 7.5 8.0

Data Constraint

对于30%的数据,N<=1000
对于100%的数据,N<=100000

Hint

样例解释:
样例1共12种遍历方法,依次如下
1 2 3 4 6 7 5
1 2 3 4 7 6 5
1 2 3 5 4 6 7
1 2 3 5 4 7 6
1 4 6 7 2 3 5
1 4 7 6 2 3 5
1 4 6 7 5 2 3
1 4 7 6 5 2 3
1 5 2 3 4 6 7
1 5 2 3 4 7 6
1 5 4 6 7 2 3
1 5 4 7 6 2 3

Solution

与昨天一样,神题!!!看看这里
另外,某人昨天第一题光看样例就看出了100分
今天接着看样例,又是100分!
对于每个点,它的值就是所有兄弟的子树大小/2+父亲的值+1
自己推一下,多设几个东西表示,再化简就变成了上面的式子

Code

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define N 101000
using namespace std;
int n,fa[N],size[N],last[N*10],next[N*10],to[N*10],tot=0;
double a[N];
void putin(int x,int y)
{
    next[++tot]=last[x];last[x]=tot;to[tot]=y;
}
void dg(int x)
{
    size[x]=1;for(int i=last[x];i;i=next[i]) dg(to[i]),size[x]+=size[to[i]];
}
void dg2(int x)
{
    for(int i=last[x];i;i=next[i])
    {
        a[to[i]]=(double)(size[x]-size[to[i]]-1)/2+a[x]+1;
        dg2(to[i]);
    }
}
int main()
{
    scanf("%d",&n);fo(i,2,n) scanf("%d",&fa[i]),putin(fa[i],i);
    dg(1);a[1]=1.0;dg2(1);
    fo(i,1,n) printf("%.1lf ",a[i]);
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值