ZROI466小 G 的数

发布于 11 天前  81 次阅读


最近从某个地方看到了这个题。。。所以回来补一下题解。

题目描述


题解

直接求期望不太好求,我们可以考虑求出每一种条件下的概率,最后乘上直径长度就可以了。
我们设 $f_{i,j,k}$ 表示在以 $i$ 为根的子树里,目前不跨过 $i$ 节点的最长链是 $j$,子树的直径是 $k$ 的概率。
转移就用树 dp 合并子树那种方法来做...枚举一下根与待合并的子树之间的边权就可以了。
转移方程就咕了,详情请参考代码。

代码

#include <algorithm>
#include <iostream>
#include <iomanip>
#include <cstring>
#include <climits>
#include <cstdlib>
#include <cstdio>
#include <bitset>
#include <vector>
#include <cmath>
#include <ctime>
#include <queue>
#include <stack>
#include <map>
#include <set>

#define fi first
#define se second
#define U unsigned
#define P std::pair
#define Re register
#define LL long long
#define pb push_back
#define MP std::make_pair
#define all(x) x.begin(),x.end()
#define CLR(i,a) memset(i,a,sizeof(i))
#define FOR(i,a,b) for(Re int i = a;i <= b;++i)
#define ROF(i,a,b) for(Re int i = a;i >= b;--i)
#define DEBUG(x) std::cerr << #x << '=' << x << std::endl
#define ld long double

const double EPS = 1e-9;
const int MAXN = 100+5;

struct Edge{
    int to,nxt;
}e[MAXN<<1];
int cnt,head[MAXN];

inline void add(int u,int v){
    e[++cnt] = (Edge){v,head[u]};head[u] = cnt;
    e[++cnt] = (Edge){u,head[v]};head[v] = cnt;
}

ld f[MAXN][MAXN][MAXN],g[MAXN][MAXN];int dep[MAXN],chain[MAXN];
inline bool cmp(int a,int b){
    return chain[a] < chain[b];
}

inline void dfs(int v,int fa){
    f[v][0][0] = 1;std::vector<int> ch;
    for(int i = head[v];i;i = e[i].nxt){
        if(e[i].to == fa) continue;
        dfs(e[i].to,v);ch.pb(e[i].to);
    }
    std::sort(all(ch),cmp);
    FOR(k,0,(int)ch.size()-1){
        int t = ch[k];
        FOR(i,0,dep[v]){
            FOR(j,0,chain[v]){
                g[i][j] = f[v][i][j];
                f[v][i][j] = 0;
            }
        }
        FOR(i1,0,dep[v]){
            FOR(j1,0,chain[v]){
                if(std::fabs(g[i1][j1]) <= EPS) continue;
                FOR(i2,0,dep[t]){
                    FOR(j2,0,chain[t]){
                        if(std::fabs(f[t][i2][j2]) <= EPS) continue;
                        ld x = g[i1][j1] * f[t][i2][j2]*0.5;
                        FOR(kk,1,2){
                            int i = std::max(i1,i2+kk),j = std::max(i1+i2+kk,std::max(j1,j2));
                            f[v][i][j] += x;
                        }
                    }
                }
            }
        }
        chain[v] = std::max(std::max(chain[v],chain[t]),dep[v]+dep[t]+2);
        dep[v] = std::max(dep[v],dep[t]+2);
    }
}

int n,a[MAXN],b[MAXN];

int main(){
    scanf("%d",&n);
    FOR(i,1,n-1){
        int u,v;scanf("%d%d",&u,&v);add(u,v);
    }
    dfs(1,0);
    ld ans = 0;
    FOR(i,0,dep[1]){
        FOR(j,0,chain[1]){
            ans += j*f[1][i][j];
        }
    }
    printf(".10Lf\n",ans);
   return 0;
}

一个OIer。