题目:
题解:
矩阵树定理,先前只知道构造方法和基本的求生成树个数
然而实际上K矩阵是这么个玩意
我们可以发现其实是跟边权有关的
其实矩阵树定理求的是
∑T∏e∈Twe
∑
T
∏
e
∈
T
w
e
然后这个题目让我们求的显然是
∑T∏e∈Tpe∏e∉T(1−pe)
∑
T
∏
e
∈
T
p
e
∏
e
∉
T
(
1
−
p
e
)
这个式子求的前半截是一样的,后半截不太一样,但是显然
∏e∉T(1−pe)=∏e(1−pe)∏e∈T(1−pe)
∏
e
∉
T
(
1
−
p
e
)
=
∏
e
(
1
−
p
e
)
∏
e
∈
T
(
1
−
p
e
)
然后就可以带进去了
∏e(1−pe)∑T∏e∈Tpe1−pe
∏
e
(
1
−
p
e
)
∑
T
∏
e
∈
T
p
e
1
−
p
e
然后我们就可以让a的权值为后面的一堆就好啦
还有就是当矩阵中出现 |a|<eps | a | < e p s 时就 a=eps a = e p s 当矩阵中出现 |1−a|<eps | 1 − a | < e p s 时就 a=1−eps a = 1 − e p s
BZOJ上的输出一定要开到1e-10才能过= =
代码:
#include <cstdio>
#include <cmath>
#include <iostream>
using namespace std;
const int N=55;
const double eps=1e-8;
double a[N][N];
double gauss(int n)
{
double ans=1;
for (int i=1;i<=n;i++)
{
int num=i;
for (int j=i+1;j<=n;j++)
if (abs(a[num][i])<abs(a[j][i])) num=j;
if (num!=i) for (int j=i;j<=n;j++) swap(a[num][j],a[i][j]);
for (int j=i+1;j<=n;j++)
{
double t=a[j][i]/a[i][i];
for (int k=i;k<=n;k++) a[j][k]-=t*a[i][k];
}
if (abs(a[i][i])<eps) return 0;
ans=ans*a[i][i];
}
return abs(ans);
}
int main()
{
int n;scanf("%d",&n);
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
scanf("%lf",&a[i][j]);
double tmp=1;
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
{
if (abs(a[i][j])<eps) a[i][j]=eps;
else if (abs(1.0-a[i][j])<eps) a[i][j]=1.0-eps;
if (i<j) tmp*=1.0-a[i][j];
a[i][j]=a[i][j]/(1.0-a[i][j]);
}
for (int i=1;i<=n;i++)
{
a[i][i]=0;
for (int j=1;j<=n;j++)
if (i!=j) a[i][i]+=a[i][j],a[i][j]=-a[i][j];
}
printf("%.10lf",tmp*gauss(n-1));
}