Problem
题意:给定图 G G 与每条边的存在概率 pi p i ,求图是一棵生成树 T T 的概率
Solution
看到这道题首先想到了 O(n22nlogn) O ( n 2 2 n log n ) 的Map+Dp
接着想到了 MatrixTree M a t r i x T r e e 定理可以套用在这个上面,试了几次后就不会了……
考虑
前面的可以 O(stdin) O ( s t d i n ) 算,后面的用 MatrixTree M a t r i x T r e e 算即可
题目难度主要在于提出公因式,可能自己对矩形树的应用还不是很熟练,所以没法第一眼看出
注意当边概率为1或0时要加减eps,否则会nan
Code
#include<bits/stdc++.h>
using namespace std;
#define rg register
const double eps=1e-8;
const int N=55;
double a[N][N],ans=1.0;
int n;
void gauss(){
double tmp=1.0;
for(rg int i=1;i<=n;++i){
int p=i;
for(rg int j=i+1;j<=n;++j)if(a[j][i]-a[p][i]>eps)p=j;
if(p!=i)for(rg int j=i;j<=n;++j)swap(a[i][j],a[p][j]);
if(a[i][i]<eps){a[i][i]=0;return ;}
for(rg int j=i+1;j<=n;++j)a[i][j]/=a[i][i];
tmp*=a[i][i];a[i][i]=1.0;
for(rg int j=i+1;j<=n;++j){
for(rg int k=i+1;k<=n;++k)
a[j][k]-=a[i][k]*a[j][i];
a[j][i]=0;
}
}a[1][1]*=tmp;
return ;
}
int main(){
scanf("%d",&n);
for(rg int i=1;i<=n;++i)
for(rg int j=1;j<=n;++j){
scanf("%lf",&a[i][j]);
if(a[i][j]==1)a[i][j]-=eps+eps;
if(a[i][j]==0)a[i][j]+=eps+eps;
}
for(rg int i=1;i<=n;++i){
a[i][i]=0;
for(rg int j=1;j<=n;++j){
if(i<j)ans*=1.0-a[i][j];
if(i!=j)a[i][j]=a[i][j]/(a[i][j]-1.0);
}
}
for(rg int i=1;i<=n;++i)
for(rg int j=1;j<=n;++j)
if(i!=j)a[i][i]-=a[i][j];
--n;gauss();
for(rg int i=1;i<=n;++i)ans*=a[i][i];
printf("%.10lf\n",ans);
return 0;
}