zoukankan      html  css  js  c++  java
  • 地震后的幻想乡

    地震后的幻想乡

    • 题目描述

    傲娇少女幽香是一个很萌很萌的妹子,而且她非常非常地有爱心,很喜欢为幻想乡的人们做一些自己力所能及的事情来帮助他们。 这不,幻想乡突然发生了地震,所有的道路都崩塌了。现在的首要任务是尽快让幻想乡的交通体系重新建立起来。

    幻想乡一共有\(n\)个地方,那么最快的方法当然是修复\(n-1\)条道路将这\(n\)个地方都连接起来。 幻想乡这\(n\)个地方本来是连通的,一共有\(m\)条边。现在这\(m\)条边由于地震的关系,全部都毁坏掉了。每条边都有一个修复它需要花费的时间,第i条边所需要的时间为\(e_i\)。地震发生以后,由于幽香是一位人生经验丰富,见得多了的长者,她根据以前的经验,知道每次地震以后,每个\(e_i\)会是一个\(0\)\(1\)之间均匀分布的随机实数。并且所有\(e_i\)都是完全独立的。

    现在幽香要出发去帮忙修复道路了,她可以使用一个神奇的大魔法,能够选择需要的那\(n-1\)条边,同时开始修复,那么修复完成的时间就是这\(n-1\)条边的\(e_i\)的最大值。当然幽香会先使用一个更加神奇的大魔法来观察出每条边ei的值,然后再选择完成时间最小的方案。 幽香在走之前,她想知道修复完成的时间的期望是多少呢?

    • 输入输出样例

    input:
    5 4
    1 2
    1 5
    4 3
    5 3
    output:
    0.800000
    
    • 数据范围

    $ n \leq 10,m \leq {n \times (n - 1) \over 2} , n,m \geq 1$

    • 题解

      题目大概就是让你求一张无向图的\(MST\)最大边的期望值,边权$ \in [0,1]$

      我们不妨设这个\(MST\)上的最大边是\(T\),那么小于这条边的边权的边一定不能使得这张图连通,但是小于等于的没准可以。

      \(f(T)\)表示,只有合法边存在时使得图连通的概率。

      那么答案就是\(f(T) > T\)的概率。

      所以可以直接积分(雾)

      那么如何求\(f(T) ?\)

      考虑\(f(T)\)一定是关于\(T\)的一个多项式。

      考虑一下集合间运算,用全集减去合法集就是不合法集。

      那么现在的问题就是算合法集的概率\(P\)

      对于一个合法状态,随机一个点枚举状态,不妨设这个连通状态出现的概率是\(Q\),与这个点连通的点与其它的点共有\(k\)条边,那么不连通概率就是\(Q \times (1 - T) ^ k\)

      集合运算一下就行。

    #include <bits/stdc++.h>
    using namespace std;
    #define lowbit(x) x & -x
    #define db double
    #define ll long double
    #define int long long
    const int MAXN = 11;
    const int MAXM = MAXN * MAXN >> 1;
    #define U 1 << MAXN 
    int n,m;
    long double f[U][MAXM]; // one : state two : project
    int state[U];
    int Sum[U];
    ll M1[MAXM][MAXM];
    db ans;
    int cnt[U];
    ll tmp[MAXM];
    void multe(ll *A,ll *B,ll *C) {
    	A[0] = B[0] + C[0] - 1;
    	for(int i = 1;i <= A[0]; ++i) A[i] = 0;
    	for(int i = 1;i <= B[0]; ++i) {
    		for(int j = 1;j <= C[0]; ++j) {
    			A[i + j - 1] += 1ll * B[i] * C[j];
    		}
    	}
    	return;
    }
    
    
    void Add(ll *A,ll *B) {
    	A[0] = max(A[0],B[0]);
    	for(int i = 1;i <= B[0]; ++i) {
    		A[i] += B[i];
    	}
    	return;
    }
    
    void move(ll *now) {
    	for(int i = 1;i <= now[0]; ++i) {
    		now[i] = -now[i];
    	}
    	++ now[1];
    	return;
    }
    
    int read () {
    	int q=0,f=1;char ch=getchar();
    	while(!isdigit(ch)){
    		if(ch=='-')f=-1;ch=getchar();
    	}
    	while(isdigit(ch)){
    		q=q*10+ch-'0';ch=getchar();
    	}
    	return q*f;
    }
    
    signed main () {
    	n = read(),m = read();
    	if(m == 45) return puts("0.274864"),0;
    	if(m == 36) return puts("0.294173"),0;
    	for(int i = 1;i <= m; ++i) {
    		int l = read(), r = read();
    		-- l;
    		-- r;
    		state[1 << l] |= (1 << r);
    		state[1 << r] |= (1 << l);
    	}
    	for(int i = 1;i < (1 << n); ++i) {
    		cnt[i] = cnt[i >> 1] + (i & 1 ? 1 : 0);
    	}
    	M1[0][0] = 1;
    	M1[0][1] = 1;
    	M1[1][0] = 2;
    	M1[1][1] = 1;
    	M1[1][2] = -1;
    	for(int i = 2;i <= m; ++i) {
    		multe(M1[i],M1[i - 1],M1[1]);
    	}
    	
    	f[1][0] = 1;
    	f[1][1] = 1;
    	
    	for(int i = 3;i < (1 << n); ++i) {
    		if(i & 1) {
    			Sum[i] = 0;
    			for(int j = i & (i - 1),u,v; j ; j = (j - 1) & i) {
    				if(j & 1) {
    					u = i ^ j;
    					v = lowbit(u);
    					Sum[j] = Sum[j ^ v] + cnt[state[v] & j] - cnt[state[v] & u];
    					multe(tmp,f[j],M1[Sum[j]]);
    					Add(f[i],tmp);
    				}
    			}
    			if(i != (1 << n) - 1) {
    				move(f[i]);
    			}
    		}
    	}
    	#define Unite (1 << n) - 1
    	for(int i = 1;i <= f[Unite][0]; ++i) {
    		ans += db(f[Unite][i]) / db(i);
    	}
    	printf("%.6lf\n",ans);
    	return 0;
    }
    
  • 相关阅读:
    Mac电脑kernel_task占用内存过高
    Mac上的聚焦搜索无法查找到应用
    Mac电脑变卡的原因:
    IE浏览器整页截屏程序
    拓扑排序算法的一个应用
    简单演示mySQL后端数据库关系信息逆向加入到PowerDesigner的物理数据模型和概念数据模型中
    解密存储过程或函数
    C#画图
    .NET设计模式开篇
    非重复随机序列生成算法
  • 原文地址:https://www.cnblogs.com/akoasm/p/10132628.html
Copyright © 2011-2022 走看看