Problem
Solution
做这道题,你需要一个前置技能,matrix tree定理
最初的想法是直接用边存在的概率构造矩阵,即D为期望度数矩阵,A为期望邻接矩阵
看起来很有道理结果发现连样例都过不了
这个时候的答案应该是期望状态下的生成树个数,由于权值为1,就相当于概率,即是
∑T∈G∏e∈Tpe
∑
T
∈
G
∏
e
∈
T
p
e
于是乎你得到的答案是0.75,而这个多出来0.375就是所有边均出现时,有三种不同的生成树,其贡献为
0.53∗3=0.375
0.5
3
∗
3
=
0.375
而题目中询问的答案是
∑T∈G∏e∈Tpe∏e∉T(1−pe)
∑
T
∈
G
∏
e
∈
T
p
e
∏
e
∉
T
(
1
−
p
e
)
考虑到枚举其他不属于树上的边很复杂,我们不妨把其提出来
预处理前面的部分,而后面的式子就是我们之前用matrix tree定理计算的式子,把元素改一改即可
注意一下0和1时,可以近似地改为eps和1-eps
BZOJ上精度可能有点问题,可能需要输出8位小数才能过
Code
#include <algorithm>
#include <cstdio>
using namespace std;
const double eps=1e-8;
int n;
double ans=1.0,a[55][55];
inline double fabs(double x){return x<0?-x:x;}
void gauss()
{
for(int i=1,r;i<n;i++)
{
r=i;
for(int j=i+1;j<n;j++)
if(fabs(a[r][i])<fabs(a[j][i]))
r=j;
if(i^r) swap(a[i],a[r]);
ans*=a[i][i];
for(int j=i+1;j<n;j++) a[i][j]/=a[i][i];
for(int j=1;j<n;j++)
if(i^j)
for(int k=i+1;k<n;k++)
a[j][k]-=a[j][i]*a[i][k];
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif
scanf("%d",&n);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
scanf("%lf",&a[i][j]);
if(a[i][j]<eps) a[i][j]=eps;
if(fabs(a[i][j]-1.0)<eps) a[i][j]=1-eps;
if(i<j) ans*=1.0-a[i][j];
a[i][j]/=(1.0-a[i][j]);
}
for(int i=1;i<=n;i++)
{
a[i][i]=0.0;
for(int j=1;j<=n;j++)
if(i^j) a[i][i]-=a[i][j];
}
gauss();
printf("%.8lf\n",fabs(ans));
return 0;
}