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