[SDOI2014]重建

P3317 [SDOI2014]重建

题解

直接M-T肯定不对

推出的是对于所有树的生成概率的和,可以考虑行列式的期望,再交换求和号即可

同时乘上π(1-P)再变化初始的概率就有点厉害了

一种变化的技巧

代码:

#include<bits/stdc++.h>
#define il inline
#define reg register int
#define numb (ch^'0')
#define ld long double
using namespace std;
typedef long long ll;
il void rd(int &x){
    char ch;bool fl=false;
    while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
    for(x=numb;isdigit(ch=getchar());x=x*10+numb);
    (fl==true)&&(x=-x);
}
namespace Miracle{
const int N=55;
const double eps=1e-8;
ld G[N][N],f[N][N];
int n;
ld GUASS(int n){
    for(reg i=1;i<=n;++i){
        int id=0;
        for(reg j=i;j<=n;++j){
            if(fabs(f[j][i])>fabs(f[id][i])) id=j;
        }
        if(id!=i){
            for(reg j=i;j<=n;++j){
                swap(f[i][j],f[id][j]);
            }
        }
        for(reg k=i+1;k<=n;++k){
            if(fabs(f[k][i])>eps){
                ld tmp=f[k][i]/f[i][i];
                for(reg j=i;j<=n;++j){
                    f[k][j]-=f[i][j]*tmp;
                }
            }
        }
    }
    ld ret=1.00;
    for(reg i=1;i<=n;++i){
        ret=ret*f[i][i];
    }
    return ret;
}
int main(){
    rd(n);
    ld tmp=1.00;
    for(reg i=1;i<=n;++i) {
        for(reg j=1;j<=n;++j){
            scanf("%Lf",&G[i][j]);
            if(fabs(G[i][j])<eps) G[i][j]=eps;
            if(fabs(1-G[i][j])<eps) G[i][j]=1-eps;
            if(i<j) tmp=tmp*(1.00-G[i][j]);
            G[i][j]=G[i][j]/(1.00-G[i][j]);
            if(i<j) f[i][i]+=G[i][j],f[j][j]+=G[i][j];
        }
    }
    for(reg i=1;i<=n;++i){
        for(reg j=1;j<=n;++j){
            f[i][j]-=G[i][j];
        }
    }
    ld ans=GUASS(n-1);
    ans=ans*tmp;
    printf("%.10Lf",ans);
    return 0;
}

}
signed main(){
    Miracle::main();
    return 0;
}

/*
   Author: *Miracle*
   Date: 2019/2/22 23:02:49
*/
原文地址:https://www.cnblogs.com/Miracevin/p/10421305.html