题目描述
https://www.luogu.com.cn/problem/P3317
简要题意:给定一个完全图,每条边的权值表示这条边存在的概率,求存在的边恰好构成一棵生成树的概率
$n\le 50$
Solution
首先容易得到答案为 $\sum_{T\in Tree}(\prod_{w\in T}p_e\prod_{w\notin T}(1-p_e))=\prod 1-p_e\sum_{T\in Tree}\sum_{e\in T}\frac{p_e}{1-p_e}$
后面那个东西用矩阵树定理来求就行了,需要注意如果 $|1-p_e|<\epsilon$,为了精度,我们需要将 $p_e$ 减掉 $\epsilon$
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
   | #include <iostream> #include <iomanip> #include <cmath> #define maxn 310 #define ll long long using namespace std;
  const double eps = 1e-8;
  double g[maxn][maxn]; double Gauss(int n) {     double res = 1;      for (int i = 1; i <= n; ++i) {         int pos = -1;         for (int j = i; j <= n; ++j)             if (fabs(g[j][i]) > fabs(g[pos][i])) pos = j;          if (pos == -1 || fabs(g[pos][i]) < eps) return 0; swap(g[i], g[pos]); res *= pos == i ? 1 : -1;         res *= g[i][i];          for (int j = i + 1; j <= n; ++j)              for (int k = n; k >= i; --k)                 g[j][k] -= g[j][i] / g[i][i] * g[i][k];     } return res; }
  int n; double a[maxn][maxn];
  int main() {     ios::sync_with_stdio(false);     cin.tie(nullptr); cout.tie(nullptr);
      cin >> n; double ans = 1;      for (int i = 1; i <= n; ++i)         for (int j = 1; j <= n; ++j) {             cin >> a[i][j];             if (a[i][j] > 1 - eps) a[i][j] -= eps;             if (i < j) ans *= 1 - a[i][j];         }     for (int i = 1; i <= n; ++i) {         double sum = 0;         for (int j = 1; j <= n; ++j) g[i][j] = -a[i][j] / (1 - a[i][j]), sum += a[i][j] / (1 - a[i][j]);         g[i][i] = sum;     } cout << fixed << setprecision(5) << ans * Gauss(n - 1) << "\n";     return 0; }
 
   |