P3830 [SHOI2012]隨機樹

P3830 [SHOI2012]隨機樹

連接ios

分析: git

  第一問:f[i]表示有i個葉子結點的時候的平均深度,$f[i] = \frac{f[i - 1] + 2 + f[i - 1] * (i - 1)}{2} $,表示新增長一個葉子結點,深度增長2,加權後取平均值。spa

  第二問:f[i][j]表示有i個葉子結點,樹的深度大於等於j的機率,有$f[i][max(k, l)+ 1] = \frac{f[j][k] \times f[i - j][l]}{i - 1}$,$ans=\sum\limits_{i = 1}^{n} i * f[n][i]$。code

  其中除以$i-1$表示i個葉子結點中,左兒子爲j個時候的機率。由於左兒子結點只有$i-1$個取值,因而每一個的機率都是$\frac{1}{i-1}$。blog

  枚舉完左兒子的葉子結點,右兒子葉子結點也就肯定了,而後左右兒子結點都是一個相同的子問題。get

代碼:string

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<iostream>
#include<cctype>
#include<set>
#include<queue>
#include<map>
#include<vector>
#include<bitset>
using namespace std;
typedef long long LL;

inline int read() {
    int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
}

const int N = 1005;
void solve1(int n) {
    static double f[N];
    for (int i = 2; i <= n; ++i) f[i] = f[i - 1] + 2.0 / i;
    printf("%.6lf\n", f[n]);
}
void solve2(int n) {
    static double f[N][N];
    f[1][0] = 1.0;
    for (int i = 2; i <= n; ++i) 
        for (int j = 1; j < i; ++j) 
            for (int k = 0; k <= j; ++k)
                for (int l = 0; l <= (i - j); ++l) 
                    f[i][max(k, l) + 1] += f[j][k] * f[i - j][l] / (i - 1);
    double ans = 0;
    for (int i = 1; i <= n; ++i) ans += i * f[n][i];
    printf("%.6lf\n", ans);
}
int main() {
    int ty = read(), n = read();
    ty == 1 ? solve1(n) : solve2(n);    
    return 0;
}
相關文章
相關標籤/搜索