做这个这个题需要稍微深入理解一点矩阵树定理:套矩阵树定理得到的东西是有意义的,它是“所有生成树边权乘积之和”(因为度数矩阵是点的边权和,邻接矩阵是边权),即$sum_{t}prod_{e∈t}v_e$,其中t是生成树集合中的树。
但是这题同时还要保证不该出现的不要出现,所以答案其实是$sum_{t}(prod_{e∈t}v_eprod_{e'∉t}(1-v_{e'}))$
怎么做?我们尝试推一波把它变成矩阵树定理的形式再套
$ans=sum_{t}(prod_{e∈t}v_eprod_{e'∉t}(1-v_{e'}))$
$=sum_{t}(prod_{e∈t}v_efrac{prod (1-v_e)}{prod_{e∈t}(1-v_e)})$
$=prod (1-v_e)(sum_{t}prod_{e∈t}frac{v_e}{1-v_e})$
注意可能会有不出现/必定出现的边,没法做除法,怎么办?
我们给他一个极小的边权,保证不影响结果,因为答案精度不是十分高=。=

1 #include<cmath> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #define double long double 6 using namespace std; 7 const int N=55; 8 const double eps=1e-10; 9 double rd,mul,equ[N][N]; int n; 10 void Correct(double &x) 11 { 12 if(x<=eps) x=eps; 13 if(1-x<=eps) x=1-eps; 14 } 15 void Guass() 16 { 17 for(int i=1;i<=n;i++) 18 { 19 int tmp=i; 20 for(int j=i+1;j<=n;j++) 21 if(fabs(equ[j][i])>fabs(equ[tmp][i])) tmp=j; 22 for(int j=i;j<=n;j++) 23 swap(equ[i][j],equ[tmp][j]); 24 for(int j=1;j<=n;j++) 25 if(i!=j) 26 { 27 double tep=equ[j][i]/equ[i][i]; 28 for(int k=i;k<=n;k++) 29 equ[j][k]-=tep*equ[i][k]; 30 } 31 } 32 } 33 int main() 34 { 35 scanf("%d",&n),mul=1; 36 for(int i=1;i<=n;i++) 37 for(int j=1;j<=n;j++) 38 { 39 scanf("%Lf",&rd),Correct(rd); 40 if(i<j) mul*=(1-rd); equ[i][j]=rd/(1-rd); 41 } 42 for(int i=1;i<=n;i++) 43 { 44 equ[i][i]=0; 45 for(int j=1;j<=n;j++) 46 if(i!=j) equ[i][i]-=equ[i][j]; 47 } 48 // for(int i=1;i<=n;i++,puts("")) 49 // for(int j=1;j<=n;j++) 50 // printf("%.2Lf ",equ[i][j]); 51 n--,Guass(); 52 for(int i=1;i<=n;i++) mul*=equ[i][i]; 53 printf("%.5Lf",abs(mul)); 54 return 0; 55 }