[cf235D]Graph Game

Description

给定一张$n$个顶点$n$条边图,定义过程$solve(G),G$是一个连通块.

$1.totalCost=totalCost+|G|,|G|$表示图$G$中的节点个数.

$2.$在图$G$中随机选择一个节点$x$(每个点被选中的概率相等).

$3.$在图$G$中删除节点$x$.

$4.$图被分裂为几个连通块.

$5.$分治处理所有的子连通块$G',solve(G')$.

求$totalCost$的数学期望.

Input

第一行一个整数$n$,表示图中点的数量和边的数量.

接下来$n$行,每行两个空格隔开的整数$a_i,b_i$,表示一条$(a_i,b_i)$的无向边.
节点从$0$开始编号.

Output

仅一行输出一个实数,表示$totalCost$的数学期望.和标准答案绝对误差或相对误差在$10^{−6}$以内都被认为正确.

Sample Input


3 4
2 3
2 4
0 4
1 2

Sample Output

13.1666666666

HINT

$n\;\leq\;3000$

Solution

  • 树的情况

定义事件$P(A,B)$为在删除点$A$时,$B$点仍与$A$点连通的概率.

显然当一个事件发生时,答案$+1$,所以答案的期望值为所有事件的总和.

$P(A,B)=$在$AB$路径上的点数的倒数.

设$AB$路径上的点数为$n$.

  • 当连通块大小$=n$时,连通块为链$AB$.只有选取$A$时才会发生事件$P(A,B)$,概率为$\frac{1}{n}$.
  • 当连通块大小$\geq\;n$,为$x$时,选取的点有两种情况:
  1. 选取在$AB$链上,这时的概率为$\frac{n}{x}\times\frac{1}{n}$;
  2. 选取不在$AB$链上,概率为$\frac{x-n}{x}\times\frac{1}{n}$.
相加为$\frac{1}{n}$.
  • 原题的情况
  • $AB$间的路径没通过环,结论同树.
  • $AB$间的路径经过了环,可以将路径上的点分成三部分:
    • 环外的点$x$,数量记为$X$.
    • 环上$A$到$B$顺时针的点$y$,数量记为$Y$.
    • 环上$B$到$A$顺时针的点$z$,数量记为$Z$.
  • 在选取$A$之前,$y,z$之间必须有一条不能被取,不能选取$x$.期望值为$\frac{1}{X+Y}+\frac{1}{X+Z}-\frac{1}{X+Y+Z}$.
#include<cmath>
#include<ctime>
#include<queue>
#include<stack>
#include<cstdio>
#include<vector>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define N 3005 
using namespace std;
struct graph{
    int nxt,to;
}e[N<<1];
int g[N],t[N],d1[N],d2[N],n,cnt;
bool ins[N];
double ans;
queue<int> q;
inline int read(){
    int ret=0;char c=getchar();
    while(!isdigit(c))
        c=getchar();
    while(isdigit(c)){
        ret=(ret<<1)+(ret<<3)+c-'0';
        c=getchar();
    }
    return ret;
}
inline void addedge(int x,int y){
    e[++cnt].nxt=g[x];g[x]=cnt;e[cnt].to=y;
}
inline void toposort(){
    int u;
    for(int i=1;i<=n;++i)
        if(t[i]==1) q.push(i);
    while(!q.empty()){
        u=q.front();q.pop();++cnt;
        for(int i=g[u];i;i=e[i].nxt)
            if((--t[e[i].to]==1))
                q.push(e[i].to);
    }
}
inline void dfs(int u){
    ins[u]=true;
    for(int i=g[u];i;i=e[i].nxt)
        if(!ins[e[i].to]){
            d2[e[i].to]=d2[u]+1;
            if(!d1[e[i].to]){
                d1[e[i].to]=d1[u]+1;
                ans+=1.0/(double)(d1[e[i].to]);
            }
            else ans+=1.0/(double)(d2[e[i].to])-2.0/(double)(d1[e[i].to]+d2[e[i].to]+cnt-2);
            dfs(e[i].to);
        }
    ins[u]=false;
}
inline void Aireen(){
    n=read();
    for(int i=1,j,k;i<=n;++i){
        j=read()+1;k=read()+1;
        addedge(j,k);addedge(k,j);
        ++t[j];++t[k];
    }
    cnt=0;toposort();cnt=n-cnt;
    for(int i=1;i<=n;++i){
        memset(d1,0,sizeof(d1));
        memset(d2,0,sizeof(d2));
        d1[i]=d2[i]=1;dfs(i);
    }
    printf("%.8lf\n",ans+n);
}
int main(){
    freopen("dac.in","r",stdin);
    freopen("dac.out","w",stdout);
    Aireen();
    fclose(stdin);
    fclose(stdout);
    return 0;
}

转载于:https://www.cnblogs.com/AireenYe/p/6269190.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值