zoukankan      html  css  js  c++  java
  • Codeforces 235D Graph Game

    题目大意

      给定一个环套树,类似于点分的过程,这样定义cost:

      solve(联通块)  

        cost+=联通块大小

        如果联通块大小=1,return

        选定一个点v,删除v

        将剩下几个联通块继续调用solve过程

      现在每次选定v的时候都是在联通块中等概率随机选定,求cost的期望值。

    题解

      这题好神……我膜的丽洁姐的题解膜了好长时间。

      首先考虑树的情况。考虑event(u,v)表示存在这样一次事件:u,v在一个联通块中,且选定了u作为本次的重心。这样的话对于event(u,v)对于答案有1的贡献。我们只要求出event(u,v)的概率,再把所有的加起来就是答案了。

      对于概率怎么求呢?首先对于一个树来说,这个概率就是u,v的路径上u是第一个被选中删去的点的概率。假如u,v之间的有n个节点(包括uv),这个概率是1/n.那么为了方便下面更一般情况的证明,我们要证的是在一条长度为n的从u到v的路径上第一个删掉的节点是u的事件(下面简称“事件”)的概率为1/n。对于这个我们可以用归纳法证明。

      首先对于只有两个点(u,v),结论毫无疑问是正确的。

      之后我们证明假如对于一个联通块的所有子图都是成立的,那么对于这个联通块也是成立的。设当前联通块有x个点,(u,v)之间有n个点。考虑当前的点应该选哪个。

        1.假设选的是(u,v)之间的点,那么只有当选中u时会发生事件,那么选中的是(u,v)之间的点且发生事件概率为1/x。

        2.假设选中的不是(u,v)之间的的点,显然选中的概率为(x-n)/x。选中之后考虑包含(u,v)的子图,根据假设再继续选下去发生事件的概率为1/n,因此选不是(u,v)之间的点且发生事件概率为(x-n)/xn

      两者相加,得到1/n。

      接下来考虑环套树的情况。首先如果(u,v)之间只有一条路,那么情况和树一样。如果(u,v)之间有两条路,我们可以这样考虑。假设(u,v)之间非环上的点数为X,(u,v)之间一条路要经过Y条环边,另一条要经过Z条环边。event(u,v)发生的概率实际上就是这两条路中u是任意一条路上第一个被删除的结点的概率。根据上面已有的结论,我们再容斥一下就可以轻易得到这个概率为1/(X+Y+1)[是第一条路径上第一个删掉的点的概率]+1/(Y+Z+1)[是第二条路径上第一个删掉的点的概率]-1/(X+Y+Z+1)[同时是两条路径上第一个删掉的点的概率]

      丽洁姐这场cf终于做完了……题目真的都很interesting啊……虽然我觉得这题最难

     1 #include <algorithm>
     2 #include <cstring>
     3 #include <cstdlib>
     4 #include <cstdio>
     5 const int N=6005;
     6 using namespace std;
     7 int q[N],next[N],vis[N],inl[N],head[N],st[N],top,tt,len,u,v,n,num,last[N];
     8 bool flag;
     9 double ans;
    10 inline void add(int u,int v)
    11 {
    12     q[++tt]=v;next[tt]=head[u];head[u]=tt;
    13 }
    14 void dfslen(int i,int pre)
    15 {
    16     if(flag)return;
    17     vis[i]=1;st[++top]=i;
    18     for(int j=head[i];j;j=next[j])
    19     {
    20         if(q[j]==pre)continue;
    21         if(flag)return;
    22         if(vis[q[j]])
    23         {
    24             for(;st[top]!=q[j];top--)inl[st[top]]=1,len++;
    25             inl[st[top]]=1;len++;flag=1;
    26             return;
    27         }
    28         dfslen(q[j],i);
    29     }
    30     top--;
    31 }
    32 void get(double y,double z)
    33 {
    34     if(z<=1)ans+=1/y;
    35     else{
    36         double x=y-z+len;
    37         ans-=1/x;
    38         if(z>=2)ans+=1/(x-(z-2));
    39         if(z<=len)ans+=1/(x-(len-z));
    40     }
    41 }
    42 void dfs(int i,int y,int z)
    43 {
    44     last[i]=num;get(y,z);
    45     for(int j=head[i];j;j=next[j])
    46         if(last[q[j]]!=num)dfs(q[j],y+1,z+inl[q[j]]);
    47 }
    48 int main()
    49 {
    50     scanf("%d",&n);
    51     for(int i=1;i<=n;i++)
    52     {
    53         scanf("%d%d",&u,&v);u++;v++;add(u,v);add(v,u);
    54     }
    55     dfslen(1,0);
    56     for(int i=1;i<=n;i++)
    57     {
    58         num++;dfs(i,1,inl[i]);
    59     }
    60     printf("%.12f",ans);
    61     return 0;
    62 }
    View Code
  • 相关阅读:
    git使用命令行方式提交代码到github或gitlab上
    如何创建AnjularJS项目
    基于react-native android的新闻app的开发
    Windows下搭建React Native Android开发环境
    python打怪之路【第一篇】:99乘法表
    python成长之路【第四篇】:装饰器
    python成长之路【第三篇】:函数
    python成长之路【第二篇】:列表和元组
    python成长之路【第一篇】:python简介和入门
    JavaScript进阶--慕课网学习笔记
  • 原文地址:https://www.cnblogs.com/oldjang/p/6758237.html
Copyright © 2011-2022 走看看