寻找【NOIP2016提高A组模拟7.17】
2016-07-17 21:31
267 查看
题目:
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的期望值。
样例输入:
第一行一个数N,表示节点数
第二行N-1个数,第i个数表示节点i+1的父节点(保证parent[i] < i)
7
1 2 1 1 4 4
样例输出:
1.0 4.0 5.0 3.5 4.5 5.0 5.0
数据范围:
对于30%的数据,N<=1000
对于100%的数据,N<=100000
剖解题目:
给一颗有根树以及树上点的关系,问所有遍历后的序列中,每个节点出现的位置的期望值。思路:
期望值的题目诶,一般就是努力推推公式之类的把。解法:
反正我对概率期望一向都不会,看来回去得恶补……这道题,可以通过组合数和一些阶乘的方法推出公式。
公式:当前节点的期望值=父亲的期望值+(Size父亲-Size当且节点-1)/2+1。(size表示这棵子树的大小(也就是这棵子树的节点数))。
然而,我现在也不会证.
代码:
#include<cstdio> #include<cstdlib> #include<algorithm> #include<cstring> #define fo(i,a,b) for(int i=a;i<=b;i++) using namespace std; const int maxn=1e5+3; int a[maxn],f[maxn][150],n,dad[maxn],num[maxn]; double ans[maxn]; bool bz[maxn]; void dfs(int x) { if (!f[x][0]) num[x]=1; else { fo(i,1,f[x][0]){ dfs(f[x][i]); num[x]+=num[f[x][i]]; } num[x]+=1; } } int main() { //freopen("T1.in","r",stdin); scanf("%d",&n); dad[1]=1; fo(i,1,n) { scanf("%d",&a[i]); f[a[i]][++f[a[i]][0]]=i+1; dad[i+1]=a[i]; } dfs(1); int h=0,t=1,d[maxn]; memset(d,0,sizeof(d)); d[1]=1; ans[1]=1.0; while (h!=t) { ++h; int u=d[h]; if (u!=1) ans[u]=ans[dad[u]]+((double)(num[dad[u]]-num[u]-1))/2+1; fo(i,1,f[u][0]) d[++t]=f[u][i]; } fo(i,1,n) printf("%.1lf ",ans[i]); // fclose(stdin); }