卧薪尝胆,厚积薄发。
SDOI2014 重建
Date: Wed Dec 12 19:33:42 CST 2018
In Category:
NoCategory
Description:
一个图,给出每条边存在的概率,问构成一棵生成树的概率。
$1\leqslant n\leqslant51$
Solution:
首先我们可以枚举树
$T$
,他的概率为:
$$
\begin{align}
&\prod_{e_i\in T}p_i\times\prod_{e_i\notin T}(1-p_i)\\
=&\prod _{e_i}(1-p_i)\prod_{e_i\in T}\frac{p_i}{1-p_i}
\end{align}
$$
后面那个显然可以用变元矩阵树定理做。
变元矩阵树定理的基尔霍夫矩阵为:
$g[i][j]=val[i][j]$
,
$g[i][i]=-\sum_{j\ne i}g[i][j]$
。
当
$p_i=1$
时设
$p_i=1-eps$
,
$p_i=0$
时
$p_i=eps$
。
Code:
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cctype>
#include<cstring>
using namespace std;
int n;
#define MAXN 52
double ans = 1.0;
double g[MAXN][MAXN];
double eps = 1e-8;
int main()
{
scanf("%d",&n);
for(int i = 1;i <= n;++i)
{
for(int j = 1;j <= n;++j)
{
scanf("%lf",&g[i][j]);
if(fabs(g[i][j]) < eps)g[i][j] = eps;
if(fabs(1.0 - g[i][j]) < eps)g[i][j] = 1 - eps;
if(i < j)ans = ans * (1 - g[i][j]);
g[i][j] = g[i][j] / (1 - g[i][j]);
}
}
for(int i = 1;i <= n;++i)
{
for(int j = 1;j <= n;++j)
{
if(i == j)continue;
g[i][i] -= g[i][j];
}
}
for(int i = 1;i < n;++i)
{
for(int j = i + 1;j < n;++j)
{
if(fabs(g[j][i]) >= fabs(g[i][i]))
{
for(int l = i;l < n;++l)swap(g[i][l],g[j][l]);
}
}
for(int j = i + 1;j < n;++j)
{
double ratio = g[j][i] / g[i][i];
for(int l = i;l < n;++l)g[j][l] -= g[i][l] * ratio;
}
ans = ans * g[i][i];
}
printf("%.8lf\n",fabs(ans));
return 0;
}
Copyright © 2020
wjh15101051
ღゝ◡╹)ノ♡