BZOJ 3534: [Sdoi2014]重建 矩阵树定理+概率
矩阵树定理求的是 $\sum_{E} \prod_{e \in E} w(e)$
平时我们求的大多数是方案数,所以就默认那个 $w(e)$ 是 $1$.
而如果我们想求所有生成树权值之和的话就让那个 $w(e)$ 变成边权.
我们在设置最开始的那个 (度数-邻接)矩阵的时候度数矩阵中 $S1_{i,i}$ 保留与 $i$ 点相连所有边之和.
然后 $S2_{i,j}$ 是 $(i,j)$ 所有连边之和即可.
code:
#include <cstring> #include <cmath> #include <cstdio> #include <algorithm> #define N 303 #define setIO(s) freopen(s".in","r",stdin) using namespace std; int n; double eps=1e-8; double a[N][N],p[N][N],tot=1; double gauss() { int i,j,k; double ans=1.0; for(i=2;i<=n;++i) { k=i; for(j=i+1;j<=n;++j) if(fabs(a[j][i])>fabs(a[k][i])) k=j; if(k!=i) swap(a[i],a[k]),ans*=-1; if(fabs(a[i][i])<eps) return 0.0; double inv=1.0/a[i][i]; for(j=i+1;j<=n;++j) { double t=a[j][i]/a[i][i]; for(k=i;k<=n;++k) a[j][k]-=t*a[i][k]; } } for(i=2;i<=n;++i) ans*=a[i][i]; return ans; } int main() { // setIO("input"); int i,j; scanf("%d",&n); for(i=1;i<=n;++i) for(j=1;j<=n;++j) scanf("%lf",&p[i][j]); for(i=1;i<=n;++i) for(j=i+1;j<=n;++j) { if(fabs(p[i][j])<eps) p[i][j]=eps; if(fabs(1-p[i][j])<eps) p[i][j]=1-eps; tot*=(1.0-p[i][j]); a[i][i]+=p[i][j]/(1.0-p[i][j]); a[j][j]+=p[i][j]/(1.0-p[i][j]); a[i][j]-=p[i][j]/(1.0-p[i][j]); a[j][i]-=p[i][j]/(1.0-p[i][j]); } double ans=gauss(); printf("%.10f\n",ans*tot); return 0; }