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;
}

浙公网安备 33010602011771号