【BZOJ】3534: [Sdoi2014]重建-变元矩阵树定理

传送门:bzoj3534


题解

由于博主还没有系统地学习过矩阵树定理的原理,只能大概地谈一下:

邻接矩阵中是可以带权的,设 w i , j w_{i,j} wi,j表示边 ( i , j ) (i,j) (i,j)的边权, e i e_i ei表示边。

矩阵中 g i , j = g j , i = w i , j , g i , i = − ∑ j ≠ i g i , j g_{i,j}=g_{j,i}=w_{i,j},g_{i,i}=-\sum \limits_{j\neq i}g_{i,j} gi,j=gj,i=wi,j,gi,i=j̸=igi,j

n − 1 n-1 n1阶主子式的值即所有生成树的边权积之和。

而此题中树 T T T的概率 = ∏ e ∈ T P e ∏ e ∉ T ( 1 − P e ) =\prod\limits_{e \in T}P_e \prod\limits_{e \notin T}(1 - P_e) =eTPee/T(1Pe)

g i , j = P ( i , j ) 1 − P ( i , j ) g_{i,j}=\dfrac{P_{(i,j)}}{1-P_{(i,j)}} gi,j=1P(i,j)P(i,j)

答案就变成了 n − 1 n-1 n1阶主子式的值 × ∏ e ( 1 − P e ) \times \prod\limits_e(1-P_e) ×e(1Pe)

p.s 注意精度


代码

#include
#define eps 1e-10
using namespace std;
typedef double db;
const int N=52;
 
int n;
db a[N][N],g[N][N],ss=1.0;
 
inline db gauss()
{
    db re=1.0,qw;int i,j,k,mx;
    for(i=1;i<n;++i){
        mx=i;
        for(j=i+1;j<n;++j)
         if(fabs(a[j][i])>fabs(a[mx][i])) mx=j;
        if(mx!=i) 
         for(j=i;j<n;++j) swap(a[mx][j],a[i][j]);
        for(k=i+1;k<n;++k)
         if(fabs(a[k][i])>eps){
            qw=a[k][i]/a[i][i];
            for(j=i;j<n;++j)
             a[k][j]-=qw*a[i][j];
         }
    }
    for(i=1;i<n;++i) re*=a[i][i];
    return fabs(re);
}
 
int main(){
    int i,j;db res;
    scanf("%d",&n);
    for(i=1;i<=n;++i)
        for(j=1;j<=n;++j)
           scanf("%lf",&g[i][j]);
    for(i=1;i<=n;++i){
        for(j=1;j<=n;++j) if(i!=j){
            g[i][j]=max(g[i][j],eps);
            g[i][j]=min(g[i][j],1.0-eps);
            if(i<j) ss*=(1.0-g[i][j]);
            a[i][j]-=g[i][j]/(1.0-g[i][j]);
        }
    }
    for(i=1;i<=n;++i){
        res=0.0;
        for(j=1;j<=n;++j) if(i!=j)
         res-=a[i][j];
        a[i][i]=res;
    }
    printf("%.10lf",gauss()*ss);
    return 0;
}

你可能感兴趣的:(---线性代数---,矩阵行列式,高斯消元)