zoukankan      html  css  js  c++  java
  • [CF1060F]Shrinking Tree

    description

    codeforces
    给一棵(n)个节点的树,每次等概率选择树中剩下边的一条进行缩边,这条边的两个端点有相同的概率被保留,求最后每个点被留下的概率。

    data range

    [nle 50 ]

    solution

    感谢Mr_Spade的博客教会了我做这道题。

    考虑一下这个缩边的过程:依次选择(n-1)条边进行缩边,缩边时可以选择这条边连接的两条节点中的任意一个保留,最后只剩下一个节点。

    可以发现在这个过程中我们并不知道最后剩下的到底是哪个节点,因此我们选择钦定最后留下的节点,每次有和它相连的边进行收缩时总是它保留下来,问题转化为求钦定的一个节点最后留下的概率。

    另外,这个过程的方案数是有限的,可以知道是(2^{n-1}(n-1)!)。那么这道题实际上变成了一道计数问题,我们只要求出使钦定的一个节点最后留下的方案数,最后再除以总方案数即可。

    将钦定最后留下的点看成整棵树的根节点,我们考虑树形(DP)
    子树的状态应该是忽略子树外的所有边,当前子树的根节点保留下来的方案数,那么我们可以知道由子树转移到父亲过程的表现如下:
    1.根节点转移到父亲节点(父亲节点被根节点所替代);
    2.在缩掉父亲节点和儿子节点之间的连边之前,缩掉了一些其他的边;
    3.缩掉了父亲节点和儿子节点之间的连边,根节点转移到儿子节点。

    由子树转移到父亲的过程就是已知到达步骤3的方案数推知到达步骤1的方案数的过程。

    由于在根节点转移到父亲节点后,我们还有可能缩掉一些其他的边,
    可以知道缩掉其他边的方案数 和 在根节点转移到父亲节点后,父节点剩下的边数有关
    那么我们显然需要在记录子数的基础上再记录一维表示边数。

    (f_{u,i})表示根节点(rt)转移到节点(u),子数(u)内还剩下(i)条边的方案数,答案即(f_{rt,n-1})
    这个状态实际上包含了两种边排列的方案:一类是此时已经缩掉的边,一类是此时还剩下的(i)条边。

    枚举其儿子节点(v),如何添加新子树(v)?
    对于一个完整的根节点从(u->v)的过程,我们还要知道在根节点转移到(v)(v)子树内剩下的边数(j)
    我们已经考虑好了缩掉前面子树中边的情况,因此只需要考虑步骤2在子树(v)中究竟缩掉了多少条边。
    设这个值为(k),那么根节点转移到(u)(v)子树内剩下的边数为(j+k)

    (f'_u)为转移后的数组(f_u),枚举(i,j,k),我们进行一下分类讨论:
    (k=0:)根节点转移到(u)时不需要缩边即转移到根节点(v),说明(u)(v)在根节点到达(u)之前就已经缩为一点。

    ((u,v))这条边只能插入(v)的子树已经被缩掉的方案中,它在方案中可以放到最前或在第((sz_v-1-i))条被缩掉的边之后((sz_v)表示(v)的子树大小),因此插入这条边的方案数为((sz_v-i));注意这条边可以随意选缩掉了哪个节点,于是方案数( imes 2);

    然后考虑将(v)的子树的缩边方案合并到(u)的子树的缩边方案,注意只能是已经缩掉的边相互合并,还未缩掉的边相互合并,于是方案数为(inom{i+j}{j}inom{sz_u-i-1+sz_v-j}{sz_v-j})
    转移方案即(f'_{u,i+j+k+1}+=f_{u,i} imes 2(sz_v-j)inom{i+j}{j}inom{sz_u-i-1+sz_v-j}{sz_v-j}f_{v,j})

    (k>0:)根节点转移到(u)后继续在子树(v)中缩了(k)条边,最后转移到根节点(v)
    注意((u,v))这条边的缩边时间和选择保留的点都已经被钦定(在继续缩(k)条边之后,只能保留根节点),因此直接使用(f'_{u,i+j+k+1}+=f_{u,i} imesinom{i+j}{j}inom{sz_u-i-1+sz_v-j}{sz_v-j}f_{v,j})转移方案。

    实现时可以存一个(g_i)表示(DP f_{u,i})后乘的一大堆东西,这样总复杂度为(O(n^4))

    Code

    #include<bits/stdc++.h>
    #define FILE "CF1060F"
    #define mp make_pair
    #define pb push_back
    #define RG register
    #define il inline
    using namespace std;
    typedef unsigned long long ull;
    typedef vector<int>VI;
    typedef long long ll;
    typedef double dd;
    const int N=52;
    il ll read(){
      RG ll data=0,w=1;RG char ch=getchar();
      while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
      if(ch=='-')w=-1,ch=getchar();
      while(ch<='9'&&ch>='0')data=data*10+ch-48,ch=getchar();
      return data*w;
    }
    il void file(){
      srand(time(NULL)+rand());
      freopen(FILE".in","r",stdin);
      freopen(FILE".out","w",stdout);
    }
    
    int n,head[N],nxt[N<<1],to[N<<1],cnt;
    il void add(int u,int v){to[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt;}
    int sz[N];dd fac[N],f[N][N],g[N],tmp[N];
    il dd C(int n,int m){return fac[n]/fac[m]/fac[n-m];}
    void dfs(int u,int ff){
      f[u][0]=sz[u]=1;
      for(RG int i=head[u];i;i=nxt[i]){
        RG int v=to[i];if(v==ff)continue;
        dfs(v,u);memset(g,0,sizeof(g));
        for(RG int j=0;j<=sz[v];j++)
          for(RG int k=0;k<=j;k++)
    	if(j>k)g[j]+=f[v][k];
    	else if(j==k)g[j]+=2*(sz[v]-j)*f[v][k];
        memset(tmp,0,sizeof(tmp));
        for(RG int j=0;j<sz[u];j++)
          for(RG int k=0;k<=sz[v];k++)
    	tmp[j+k]+=f[u][j]*g[k]*C(j+k,j)*C(sz[u]-j-1+sz[v]-k,sz[u]-j-1);
        memcpy(f[u],tmp,sizeof(f[u]));
        sz[u]+=sz[v];
      }
    }
    
    int main()
    {
      n=read();fac[0]=1;
      for(RG int i=1;i<=n;i++)fac[i]=fac[i-1]*i*2;
      for(RG int i=1,u,v;i<n;i++){
        u=read();v=read();add(u,v);add(v,u);
      }
      for(RG int i=1;i<=n;i++){
        memset(f,0,sizeof(f));
        dfs(i,0);
        printf("%.10lf
    ",f[i][n-1]/fac[n-1]);
      }
      return 0;
    }
    
    
  • 相关阅读:
    bzoj1861 [Zjoi2006]Book 书架
    bzoj1208 [HNOI2004]宠物收养所
    bzoj1588 [HNOI2002]营业额统计
    bzoj3295 [Cqoi2011]动态逆序对
    bzoj2716 [Violet 3]天使玩偶
    bzoj1176 [Balkan2007]Mokia
    bzoj3262 陌上花开
    spoj FTOUR2
    bzoj2152 聪聪可可
    poj1741 Tree
  • 原文地址:https://www.cnblogs.com/cjfdf/p/9762148.html
Copyright © 2011-2022 走看看