7.19T2

B small tree
Topic background and meaning of the questions
B has a small tree, it has the same shape and OI in the tree, there are n nodes, n-1 sides, each side length of 1 over time grow the tree, each side 50 length becomes 2% probability 
Small B want to know how much is desired diameter tree, but he was not too dishes, so you come for advice
Input Format
N represents a number of the first row of the tree point
Next, n-1 lines of two integers, indicates that an edge
Output Format
A real number, the diameter of the desired
data range
Packing, a total of 10 packets, the i-th bag n = i * 5 + 10
 

sol: seniors write a good solution to a problem that he can understand, he is to write it sucks (detailed notes, written at that hanging ts a year)

upd: feel all the fp

#include <bits/stdc++.h>
using namespace std;
typedef int ll;
inline ll read()
{
    ll s=0; bool f=0; char ch=' ';
    while(!isdigit(ch)) {f|=(ch=='-'); ch=getchar();}
    while(isdigit(ch)) {s=(s<<3)+(s<<1)+(ch^48); ch=getchar();}
    return (f)?(-s):(s);
}
#define R(x) x=read()
inline void write(ll x)
{
    if(x<0) {putchar('-'); x=-x;}
    if(x<10) {putchar(x+'0'); return;}
    write(x/10); putchar((x%10)+'0');
}
#define W(x) write(x),putchar(' ')
#define Wl(x) write(x),putchar('\n')
const int N=75,M=150;
int n,mx[N],sz[N];
/*
    mx[i]表示包括i在内的以i为根的子树中的最长链
    sz[i]表示以i为根的子树大小 
*/
int tot=0,Next[M],to[M],head[N];
double dp[N][M][M],f[2][M][M][M],ans=0.0;
/*
    dp[i][j][k]表示i的子树,最大深度为j,直径<=k的概率 做的时候按照直径=k做,然后搞一遍前缀和即可
    f[i][j][k][l]表示在x的子树中前i个儿子的子树中,最长链为j,次长链为k,直径<=l的概率(因为是从dp转移过来的,直接带前缀和)
*/
inline void Link(int x,int y)
{
    Next[++tot]=head[x]; to[tot]=y; head[x]=tot;
}
inline void dfs(int x,int fat)
{
    int e,i,j,k,l,t;
    sz[x]=1;
    for(e=head[x];e;e=Next[e]) if(to[e]!=fat)
    {
        dfs(to[e],x); sz[x]+=sz[to[e]];
    }
    for(i=0;i<=sz[x]*2;i++) f[t=0][0][0][i]=1.0;
    for(e=head[x];e;e=Next[e]) if(to[e]!=fat)
    {
        int V=to[e];
        t^=1;
        for(i=0;i<=mx[V];i++) for(j=1;j<=(sz[x]*2);j++) dp[V][i][j]+=dp[V][i][j-1];//前缀和
        //注意这里j要转移到sz[x]*2而不是sz[V]*2,虽然后面对于V而言没有数值,但在x转移是要用啊!!!!! 
        for(i=0;i<=mx[x];i++) for(j=0;j<=i;j++) for(k=0;k<=sz[x]*2;k++)//最长链,次长链,直径(不一定要求一定直径最长)
        {
            double tmp=f[t^1][i][j][k];
            f[t^1][i][j][k]=0; //要加入一个新儿子了
            for(l=0;l<=mx[V];l++)//枚举V中的最长链长度 
            {
                double val=dp[V][l][k]*0.5;//0.5是要分类转移
                
                if(l+1>i) f[t][l+1][i][k]+=tmp*val;
                else if(l+1>j) f[t][i][l+1][k]+=tmp*val;
                else f[t][i][j][k]+=tmp*val;
                
                if(l+2>i) f[t][l+2][i][k]+=tmp*val;
                else if(l+2>j) f[t][i][l+2][k]+=tmp*val;
                else f[t][i][j][k]+=tmp*val;
            }
        }
        mx[x]=max(mx[x],mx[V]+2);
    }
//    printf("%d %d %lf %lf ",x,mx[x],f[t][mx[x]][0][mx[x]],f[t][mx[x]][0][mx[x]-1]);
    for(i=0;i<=mx[x];i++) for(j=0;j<=i;j++) for(k=sz[x]*2;k>=0;k--)
    {
        if(k!=0) f[t][i][j][k]-=f[t][i][j][k-1];
        dp[x][i][max(i+j,k)]+=f[t][i][j][k];
        f[t][i][j][k]=0;
    }
//    printf("%lf %lf\n",dp[x][mx[x]][mx[x]],dp[x][mx[x]][mx[x]-1]);
}
int main()
{
    freopen("tree.in","r",stdin);
    freopen("tree.out","w",stdout);
    int i,j,x,y;
    R(n);
    for(i=1;i<n;i++)
    {
        R(x); R(y); Link(x,y); Link(y,x);
    }
    dfs(1,0);
//    printf("%lf %lf %lf %lf %lf\n",dp[1][4][4],dp[1][5][5],dp[1][6][6],dp[1][7][7],dp[1][8][8]);
//    for(i=1;i<=n;i++) cout<<i<<' '<<mx[i]<<' '<<sz[i]<<endl;
    for(i=0;i<=mx[1];i++) for(j=1;j<=n*2;j++) ans+=dp[1][i][j]*j;
    printf("%lf\n",ans);
    return 0;
}
View Code

 

Guess you like

Origin www.cnblogs.com/gaojunonly1/p/11222264.html