[bzoj3534][Sdoi2014]重建【矩阵树定理】【概率与期望】

【题目链接】
  https://www.lydsy.com/JudgeOnline/problem.php?id=3534
【题解】
  首先当边权不为整数时,矩阵树定理也是适用的。
  但求出来的结果是每棵树在图中出现的概率和,没有保证其他边不出现在树上。
  因此对于每一种情况,还要再乘以其他边都不在的概率。
  所以可以把每条边的边权设置为 P/(1P) P / ( 1 − P ) ,然后把最后的答案乘以 1Pi ∑ 1 − P i
  相当于先乘上所有边都不在的概率,然后除掉选上的边的概率。
  时间复杂度 O(n2) O ( n 2 )
【代码】

# include 
# define    ll      long long
# define    inf     0x3f3f3f3f
# define    N       51
# define    eps     1e-10
using namespace std;
int read(){
    int tmp = 0, fh = 1; char ch = getchar();
    while (ch < '0' || ch > '9') {if (ch == '-') fh = -1; ch = getchar(); }
    while (ch >= '0' && ch <= '9'){tmp = tmp * 10 + ch - '0'; ch = getchar(); }
    return tmp * fh;
}
double mp[N][N], ans;
int n;
void guass(int num){
    for (int i = 1; i <= num; i++){
        int mx = i;
        for (int j = i + 1; j <= num; j++)
            if (fabs(mp[j][i]) > fabs(mp[mx][i])) mx = j;
        if (mx != i){
            ans *= -1;
            for (int j = 1; j <= num; j++)
                swap(mp[mx][j], mp[i][j]);
        }
        for (int j = i + 1; j <= num; j++){
            double t = mp[j][i] / mp[i][i];
            for (int k = i; k <= num; k++) 
                mp[j][k] = mp[j][k] - t * mp[i][k];
        }
    }
} 
double det(int num){
    ans=1;
    guass(num - 1);
    for (ll i = 1; i < num; i++)
        ans=ans * mp[i][i];
    return ans;
}
int main(){
//  freopen(".in", "r", stdin);
//  freopen(".out", "w", stdout);
    n = read();
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++){
            scanf("%lf", &mp[i][j]);
            if (mp[i][j] == 1) mp[i][j] = (1 - eps);
            if (mp[i][j] == 0) mp[i][j] = eps;
        }
    double p = 1;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= i - 1; j++){
            p = p * (1 - mp[i][j]);
            mp[i][j] = mp[j][i] = -mp[i][j] / (1 - mp[i][j]);
            mp[i][i] -= mp[i][j];
            mp[j][j] -= mp[i][j];
        }
    printf("%.20lf\n", det(n) * p);
    return 0;
}


你可能感兴趣的:(【矩阵树定理】,【概率与期望】)