传送门:bzoj3534
由于博主还没有系统地学习过矩阵树定理的原理,只能大概地谈一下:
邻接矩阵中是可以带权的,设 w i , j w_{i,j} wi,j表示边 ( i , j ) (i,j) (i,j)的边权, e i e_i ei表示边。
矩阵中 g i , j = g j , i = w i , j , g i , i = − ∑ j ≠ i g i , j g_{i,j}=g_{j,i}=w_{i,j},g_{i,i}=-\sum \limits_{j\neq i}g_{i,j} gi,j=gj,i=wi,j,gi,i=−j̸=i∑gi,j
n − 1 n-1 n−1阶主子式的值即所有生成树的边权积之和。
而此题中树 T T T的概率 = ∏ e ∈ T P e ∏ e ∉ T ( 1 − P e ) =\prod\limits_{e \in T}P_e \prod\limits_{e \notin T}(1 - P_e) =e∈T∏Pee∈/T∏(1−Pe)
设 g i , j = P ( i , j ) 1 − P ( i , j ) g_{i,j}=\dfrac{P_{(i,j)}}{1-P_{(i,j)}} gi,j=1−P(i,j)P(i,j)
答案就变成了 n − 1 n-1 n−1阶主子式的值 × ∏ e ( 1 − P e ) \times \prod\limits_e(1-P_e) ×e∏(1−Pe)
p.s 注意精度
#include
#define eps 1e-10
using namespace std;
typedef double db;
const int N=52;
int n;
db a[N][N],g[N][N],ss=1.0;
inline db gauss()
{
db re=1.0,qw;int i,j,k,mx;
for(i=1;i<n;++i){
mx=i;
for(j=i+1;j<n;++j)
if(fabs(a[j][i])>fabs(a[mx][i])) mx=j;
if(mx!=i)
for(j=i;j<n;++j) swap(a[mx][j],a[i][j]);
for(k=i+1;k<n;++k)
if(fabs(a[k][i])>eps){
qw=a[k][i]/a[i][i];
for(j=i;j<n;++j)
a[k][j]-=qw*a[i][j];
}
}
for(i=1;i<n;++i) re*=a[i][i];
return fabs(re);
}
int main(){
int i,j;db res;
scanf("%d",&n);
for(i=1;i<=n;++i)
for(j=1;j<=n;++j)
scanf("%lf",&g[i][j]);
for(i=1;i<=n;++i){
for(j=1;j<=n;++j) if(i!=j){
g[i][j]=max(g[i][j],eps);
g[i][j]=min(g[i][j],1.0-eps);
if(i<j) ss*=(1.0-g[i][j]);
a[i][j]-=g[i][j]/(1.0-g[i][j]);
}
}
for(i=1;i<=n;++i){
res=0.0;
for(j=1;j<=n;++j) if(i!=j)
res-=a[i][j];
a[i][i]=res;
}
printf("%.10lf",gauss()*ss);
return 0;
}