正题
题目链接:https://www.luogu.com.cn/problem/P3317
题目大意
个点若干条边。告诉你每条边出现的概率,求刚好出现一颗生成树的概率是多少。
解题思路
矩阵树定理是计算每个生成树的每条边乘积之和。
我们考虑将答案转换为那个形式,
表示
的边出现的概率,那么对于每棵生成树有答案
也就是
所以我们先计算出所有的
的乘积,然后再将边权变为
用矩阵树计算即可。
时间复杂度
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int N=51;
const double eps=1e-8;
int n;
double a[N][N],ans;
void Gauss(){
for(int i=1;i<n;i++){
int mx=i;
for(int j=i+1;j<n;j++)
if(fabs(a[j][i])>fabs(a[mx][i]))
mx=j;
if(mx!=i)
for(int j=1;j<n;j++)
swap(a[i][j],a[mx][j]);
for(int j=i+1;j<n;j++){
double mul=a[j][i]/a[i][i];
for(int k=i;k<n;k++)
a[j][k]-=a[i][k]*mul;
}
if(fabs(a[i][i])<eps){
ans=0;return;
}
}
for(int i=1;i<n;i++)
ans=ans*a[i][i];
ans=fabs(ans);
}
int main()
{
scanf("%d",&n);ans=1;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
scanf("%lf",&a[i][j]);
if(a[i][j]<eps) a[i][j]=eps;
if(1-a[i][j]<eps) a[i][j]=1-eps;
if(i<j) ans*=1-a[i][j];
a[i][j]=a[i][j]/(1-a[i][j]);
}
for(int i=1;i<=n;i++){
a[i][i]=0;
for(int j=1;j<=n;j++)
if(i!=j)
a[i][i]-=a[i][j];
}
Gauss();
printf("%.10lf",ans);
}