列表

详情


NC20517. [ZJOI2015]地震后的幻想乡

描述

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

输入描述

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

输出描述

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

示例1

输入:

5 4
1 2
1 5
4 3
5 3

输出:

0.800000

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

Python3 解法, 执行用时: 284ms, 内存消耗: 5792K, 提交时间: 2023-08-05 09:28:20

def solve(n, m):
    lim = 1 << n
    link = [0] * n
    siz = [0] * lim
    f = [[0.0] * (m + 1) for _ in range(lim)]
    
    for i in range(m):
        x, y = map(int, input().split())
        x -= 1
        y -= 1
        link[x] |= (1 << y)
        link[y] |= (1 << x)
    
    for S in range(1, lim):
        siz[S] = siz[S & (S - 1)] + 1
    
    for S1 in range(3, lim):
        if S1 & 1:
            S2 = (S1 - 1) & S1
            while S2 != 0:
                if S2 & 1:
                    T = sum(siz[link[i] & S2] for i in range(n) if ((S1 >> i) & (~S2 >> i) & 1))
                    for i in range(m - T, -1, -1):
                        f[S1][i] += 1.0 / (i + T + 1) - f[S2][i + T]
                S2 = (S2 - 1) & S1
    
    return f[lim - 1][0]

n, m = map(int, input().split())
result = solve(n, m)
print("{:.6f}".format(result))

C++11(clang++ 3.9) 解法, 执行用时: 7ms, 内存消耗: 868K, 提交时间: 2020-03-24 14:36:33

#include <bits/stdc++.h>
using namespace std;
const int N = 10;
const int M = 45 + 1;
bool vis[1 << N][M];
int siz[1 << N], link[N];
double f[1 << N][M];
int main() {
  int n, m;
  scanf("%d%d", &n, &m);
  int lim = 1 << n;
  for (int i = 0, x, y; i < m; ++i) {
    scanf("%d%d", &x, &y);
    --x; --y;
    link[x] |= (1 << y);
    link[y] |= (1 << x);
  }
  for (int S = 1; S < lim; ++S) siz[S] = siz[S & (S - 1)] + 1;
  for (int S1 = 3; S1 < lim; ++S1) if (S1 & 1) {
    for (int S2 = (S1 - 1) & S1; S2 != 0; S2 = (S2 - 1) & S1) if (S2 & 1) {
      int T = 0;
      for (int i = 0; i < n; ++i) if ((S1 >> i) & (~S2 >> i) & 1)
        T += siz[link[i] & S2];
      for (int i = 0; i + T <= m; ++i)
        f[S1][i] += 1.0 / (i + T + 1) - f[S2][i + T];
    }
  }
  printf("%.6lf\n", f[lim - 1][0]);
  return 0;
}

上一题