• 235D Graph Game


    传送门

    题目大意

    https://www.luogu.org/problemnew/show/CF235D

    分析

    我们先考虑它是树的情况

    我们设$event(x,y)$表示删除点x是y与x联通这件事对答案贡献的期望

    我们设x到y这一条链的长度为$len$,$x$和$y$所属联通块的大小为$n$

    则我们可以猜测$event$的值为$frac{1}{len}$

    我们可以用数学归纳法证明

    我们知道直接选到$x$的概率为$frac{1}{n}$

    先选到其它点再通过若干步选到x的概率为$frac{n-len}{n} * frac{1}{len}$

    由此得证

    于是我们在考虑它是基环树的情况

    我们不难发现对于不经过环的路径没有影响

    而其它路径我们把它不经过环的那些距离设为$x$,经过环的两条路分别为$y$和$z$

    $event(x,y)$发生的概率实际上就是这两条路中$x$是任意一条路上第一个被删除的结点的概率

    我们再容斥一下就可以得到$event(x,y) = frac{1}{x+y} + frac{1}{x+z} - frac{1}{x+y+z}$

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<algorithm>
    #include<cctype>
    #include<cmath>
    #include<cstdlib>
    #include<queue>
    #include<ctime>
    #include<vector>
    #include<set>
    #include<map>
    #include<stack>
    using namespace std;
    int n,m,dep[5000],id[5000],cnt,sum,acc[5000],lca[3020][3020],f[5000];
    int dfn[5000],low[5000],ist[5000],belong[5000],tot[5000],maxid;
    double Ans;
    stack<int>a;
    vector<int>v[5000];
    inline void tarjan(int x,int fa){
        dfn[x]=low[x]=++cnt;
        a.push(x);
        ist[x]=1;
        for(int i=0;i<v[x].size();i++)
          if(v[x][i]!=fa){
            if(!dfn[v[x][i]]){
                tarjan(v[x][i],x);
                low[x]=min(low[x],low[v[x][i]]);
            }else if(ist[v[x][i]]){
                low[x]=min(low[x],dfn[v[x][i]]);
            }
          }
        if(low[x]==dfn[x]){
          sum++;
          while(1){
              int u=a.top();
              a.pop();
              ist[u]=0;
              belong[u]=sum;
              tot[sum]++;
              if(u==x)break;
          }
        }
    }
    inline int sf(int x){return f[x]==x?x:f[x]=sf(f[x]);}
    inline void work(int x,int ac,int fa){
        acc[x]=ac;
        f[x]=x;
        for(int i=0;i<v[x].size();i++)
          if(v[x][i]!=fa&&tot[belong[v[x][i]]]==1){
              dep[v[x][i]]=dep[x]+1;
              work(v[x][i],ac,x);
              if(sf(v[x][i])!=sf(x))
              f[sf(v[x][i])]=sf(x);
          }
        for(int i=1;i<=n;i++)
          if(acc[i]==ac)lca[x][i]=lca[i][x]=sf(i);
    }
    inline void dfs(int x,int fa){
        id[x]=id[fa]+1,dep[x]=1,acc[x]=x;
        work(x,x,x);
        for(int i=0;i<v[x].size();i++)
          if(v[x][i]!=fa&&!id[v[x][i]]){
              if(tot[belong[v[x][i]]]>1)dfs(v[x][i],x);
          }
    }
    int main(){
        int i,j,k,x,y;
        scanf("%d",&n);
        for(i=1;i<=n;i++){
          scanf("%d%d",&x,&y);
          x++,y++;
          v[x].push_back(y);
          v[y].push_back(x);
        }
        for(i=1;i<=n;i++)
          if(!dfn[i])tarjan(i,0);
        for(i=1;i<=n;i++)
          if(tot[belong[i]]>1){
              id[i]=1;
              maxid=tot[belong[i]];
              dfs(i,0);
              break;
          }
       for(i=1;i<=n;i++)
          for(j=1;j<=n;j++){
              if(acc[i]==acc[j])Ans+=1.0/(dep[i]+dep[j]-2*dep[lca[i][j]]+1);
                else {
                    int x=dep[i]+dep[j],y=abs(id[acc[i]]-id[acc[j]])-1,z=maxid-y-2;
                    Ans+=1.0/(x+y)+1.0/(x+z)-1.0/(x+y+z);
                }
          }
        printf("%0.7lf
    ",Ans);
        return 0;
    }
  • 相关阅读:
    【算法习题】青蛙跳台阶
    【转】从PowerDesigner概念设计模型(CDM)中的3种实体关系说起
    redis常用链接
    读书笔记——《redis入门指南(第2版)》第四章 进阶——4.1-5
    查询linux计算机的出口ip
    读书笔记——《redis入门指南(第2版)》第三章 入门
    vmware中的linux虚拟机配置以nat模式上网,并用xshell连接该虚拟机
    每日代码系列(1)
    第一次尝试自己编写
    原型模式
  • 原文地址:https://www.cnblogs.com/yzxverygood/p/10406215.html
Copyright © 2020-2023  润新知