zoukankan      html  css  js  c++  java
  • bzoj 3925: [Zjoi2015]地震后的幻想乡

    Description

     傲娇少女幽香是一个很萌很萌的妹子,而且她非常非常地有爱心,很喜欢为幻想乡的人们做一些自己力所能及的事情来帮助他们。 这不,幻想乡突然发生了地震,所有的道路都崩塌了。现在的首要任务是尽快让幻想乡的交通体系重新建立起来。幻想乡一共有n个地方,那么最快的方法当然是修复n-1条道路将这n个地方都连接起来。 幻想乡这n个地方本来是连通的,一共有m条边。现在这m条边由于地震的关系,全部都毁坏掉了。每条边都有一个修复它需要花费的时间,第i条边所需要的时间为ei。地震发生以后,由于幽香是一位人生经验丰富,见得多了的长者,她根据以前的经验,知道每次地震以后,每个ei会是一个0到1之间均匀分布的随机实数。并且所有ei都是完全独立的。 现在幽香要出发去帮忙修复道路了,她可以使用一个神奇的大魔法,能够选择需要的那n-1条边,同时开始修复,那么修复完成的时间就是这n-1条边的ei的最大值。当然幽香会先使用一个更加神奇的大魔法来观察出每条边ei的值,然后再选择完成时间最小的方案。 幽香在走之前,她想知道修复完成的时间的期望是多少呢? 

    Input

    第一行两个数n,m,表示地方的数量和边的数量。其中点从1到n标号。 
    接下来m行,每行两个数a,b,表示点a和点b之间原来有一条边。 
    这个图不会有重边和自环。 

    Output

    一行输出答案,四舍五入保留6位小数。 

    Sample Input

    5 4
    1 2
    1 5
    4 3
    5 3

    Sample Output

    0.800000

    HINT

    提示: 


    (以下内容与题意无关,对于解题也不是必要的。) 

    对于n个[0,1]之间的随机变量x1,x2,...,xn,第k小的那个的期望值是k/(n+1)。 


    样例解释: 

    对于第一个样例,由于只有4条边,幽香显然只能选择这4条,那么答案就是4条边的ei中最大的数的期望,由提示中的内容,可知答案为0.8。 


    数据范围: 

    对于所有数据:n<=10, m<=n(n-1)/2, n,m>=1。
    对于15%的数据:n<=3。
    另有15%的数据:n<=10, m=n。
    另有10%的数据:n<=10, m=n(n-1)/2。
    另有20%的数据:n<=5。
    另有20%的数据:n<=8。

    Source

    期望神题+串珠子;

    我们是要求mst上最大边权的期望,然后题目里面给了我们一个很有道理的公式:

    对于n个[0,1]之间的随机变量x1,x2,...,xn,第k小的那个的期望值是k/(n+1)。;

    有了这个式子之后我们就只关心排名了,因为知道排名就可以算出期望,推一下式子:

    其中v(x)为mst最大边排名为x的期望值,p(x)为mst最大边排名为x的概率;

    排名恰好为x的概率并不好求,但是排名>=x的概率还是很好求的,设为f(x),这等价于用排名严格小于x的边不能使图联通的概率;

    那么显然p(x)=f(x-1)-f(x),答案的式子变为:


    我们发现这个就是:

    然后我们考虑如何求f(x),我们考虑串珠子那个题子集dp的做法;

    我们设f[s][i]表示点集s中连i条边使其不连通的方案数,g[s][i]表示点集s中连i条边使其连通的方案数;

    那么显然f[s][i]+g[s][i]=C(e[s],i),其中e[s]表示点集s内部的边数;

    我们考虑如何求f[s][i],就是类似串珠子的子集dp,任取s中的一个点把他放到一个连通块(s的真子集)zt,然后算s和zt不连通的方案数;

    其实我们并不是很清楚这样为啥不会算漏,但cjk会;

    那么转移方程还是很简单了:

    即在zt中连i条边,在s去掉zt后的点集内部中连j条边;

    //MADE BY QT666
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    typedef long long ll;
    const int N=100050;
    double c[1050][1050],f[1<<10][1050],g[1<<10][1050];
    int e[1<<10],to[N],sz[1<<10];
    int main(){
        int n,m;scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++){
    	int a,b;scanf("%d%d",&a,&b);
    	to[a]+=(1<<(b-1));to[b]+=(1<<(a-1));
        }
        for(int s=0;s<(1<<n);s++){
    	for(int i=1;i<=n;i++) if(s&(1<<(i-1))) sz[s]++;
        }
        for(int s=0;s<(1<<n);s++){
    	for(int i=1;i<=n;i++){
    	    if(s&(1<<(i-1))) e[s]+=sz[to[i]&s];
    	}
    	e[s]>>=1;
        }
        for(int i=0;i<=m;++i) c[i][0]=1;
        for(int i=1;i<=m;++i)
    	for(int j=1;j<=i;++j){
    	    c[i][j]=c[i-1][j-1]+c[i-1][j];
    	}
        for(int s=0;s<(1<<n);s++){
    	if(sz[s]==1) g[s][0]=1;
    	else{
    	    int p=s&-s;
    	    for(int zt=(s-1)&s;zt;zt=(zt-1)&s){
    		if(zt&p){
    		    for(int i=0;i<=e[zt];i++){
    			for(int j=0;j<=e[s^zt];j++){
    			    f[s][i+j]+=g[zt][i]*c[e[s^zt]][j];
    			}
    		    }
    		}
    	    }
    	    for(int i=0;i<=e[s];i++) g[s][i]=c[e[s]][i]-f[s][i];
    	}
        }
        double ans=0;
        for(int i=0;i<=m;i++){
    	ans+=f[(1<<n)-1][i]/c[e[(1<<n)-1]][i];
        }
        printf("%.6f
    ",ans/(m+1));
        return 0;
    }
    
  • 相关阅读:
    AtCoder Beginner Contest 205
    Codeforces Round #725 (Div. 3)
    Educational Codeforces Round 110 (Rated for Div. 2)【A
    Codeforces Round #722 (Div. 2)
    AtCoder Beginner Contest 203(Sponsored by Panasonic)
    AISing Programming Contest 2021(AtCoder Beginner Contest 202)
    PTA 520 钻石争霸赛 2021
    Educational Codeforces Round 109 (Rated for Div. 2)【ABCD】
    AtCoder Beginner Contest 200 E
    Educational Codeforces Round 108 (Rated for Div. 2)【ABCD】
  • 原文地址:https://www.cnblogs.com/qt666/p/7659487.html
Copyright © 2011-2022 走看看