洛谷 P3317 [SDOI2014]重建(矩阵树定理)

题目描述

https://www.luogu.org/problemnew/show/P3317

给出一个图每条边存在的概率,求恰好生成一棵树的概率。(1 < N < =50)


思路

这题让我对矩阵树定理有了新的更本质的认识。

地球人都知道,基尔霍夫矩阵的任意n-1阶代数余子式就是生成树数量。这代表基尔霍夫矩阵的代数余子式皆相同且与余子式绝对值相等。

其实基尔霍夫矩阵在计算的东西是生成树每条边权的乘积的和。由于缺省值为1,所以和就是个数。在这题我们在边上放概率,可以尝试求出生成一棵树的概率和。

我们要求的无非是它( T 是生成树)

TeTpeeT(1pe)

=TeTpe(1pe)eT(1pe)

=(1pe)TeTpe1pe

我们将右边那一坨作为新的边权,然后求高消求代数余子式即可。

对了,如果 pe=1 呢?此时 11pe= ,因为 1Eps= ,直接让 pe=Eps 即可。


代码

#include <bits/stdc++.h>
#define Eps 1e-10
#define maxn 55

using namespace std;

double G[maxn][maxn], A[maxn][maxn], Violet = 1.0;

int n;

double Det(){
    int rev = 0;
    double ans = 1.0;
    for(int i = 2; i <= n; i++){
        int x = i;
        for(; x <= n && fabs(A[x][i]) < Eps; x++);

        if(x != i)  rev ^= 1, swap(A[x], A[i]);
        if(fabs(A[i][i]) < Eps)  return 0.0;
        ans *= A[i][i];

        for(int j = i+1; j <= n; j++){
            if(fabs(A[j][i]) < Eps)  continue;
            double Mul = A[j][i] / A[i][i];
            for(int k = 2; k <= n; k++)
                A[j][k] -= A[i][k] * Mul;
        }
    }
    if(rev)  return -ans;
    return ans;
}

int main(){

    scanf("%d", &n);

    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= n; j++){
            scanf("%lf", &G[i][j]);
            if(i >= j)  continue;
            if(fabs(G[i][j] - 1.0) < Eps)  G[i][j] -= Eps;
            double P = G[i][j] / (1.0 - G[i][j]);
            A[i][j] -= P;
            A[j][i] -= P;
            A[i][i] += P;
            A[j][j] += P;
            Violet *= 1.0 - G[i][j];
        }   

    printf("%.7lf\n", Violet * Det());

    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值