luoguP3317 [SDOI2014]重建 变元矩阵树定理 + 概率

 

首先,我们需要求的是

$$\sum\limits_{Tree} \prod\limits_{E \in Tree} E(u, v) \prod\limits_{E \notin Tree} (1 - E(u, v))$$

我们知道变元矩阵树定理 ---> 不知道请见此

我们自然希望要求和的事物只跟生成树的边有关

因此考虑把$\prod\limits_{E \notin Tree} (1 - E(u, v))$转化为$\prod\limits_{E} (1 - E(u, v)) * \frac{1}{\prod\limits_{E \in Tree} (1 - E(u, v))}$

也就是说,我们定义$e(u, v) = \frac{p(u, v)}{1 - p(u, v)}$

然后就是变元矩阵树定理的裸题了......

复杂度$O(n^3)$

#include <cstdio>
#include <iostream>
using namespace std;

#define sid 55
#define ri register int
#define le long double
#define eps 1e-9

int n;
le all = 1, g[sid][sid], p[sid][sid];

le abs(le a) { return (a > 0) ? a : -a; }

le Guass() {
    for(ri i = 1; i < n; i ++) {
        int p = i;
        for(ri j = i; j < n; j ++)
        if(abs(g[j][i]) - abs(g[p][i]) > eps) p = j;
        swap(g[i], g[p]);
        for(ri j = i + 1; j < n; j ++) {
            le t = g[j][i] / g[i][i];
            for(ri k = i; k < n; k ++)
            g[j][k] -= g[i][k] * t;
        }
    }
    le ret = 1;
    for(ri i = 1; i < n; i ++) ret *= g[i][i];
    return ret;
}

int main() {
    cin >> n;
    for(ri i = 1; i <= n; i ++)
    for(ri j = 1; j <= n; j ++)
    cin >> p[i][j];
    for(ri i = 1; i <= n; i ++)
    for(ri j = 1; j <= n; j ++) {
        if(i == j) continue;
        if(p[i][j] > 1 - eps) p[i][j] = p[i][j] - eps;
        if(i < j) all *= (1 - p[i][j]);
        g[i][j] = p[i][j] / (1 - p[i][j]);
    }
    for(ri i = 1; i <= n; i ++)
    for(ri j = 1; j <= n; j ++)
    if(i != j) {
        g[i][i] += g[i][j];
        g[i][j] = -g[i][j];
    }
    printf("%.8Lf\n", Guass() * all);
    return 0;
}

 

posted @ 2018-08-21 17:55  remoon  阅读(436)  评论(0编辑  收藏  举报