qwq
一开始想了个错的做法。
哎
直接开始说比较正确的做法吧。
首先我们考虑题目的
a
n
s
ans
ans该怎么去求
我们令
x
x
x表示原图中的某一条边
a n s = ∑ ∏ x ∈ t r e e p x ∏ x n o t ∈ t r e e ( 1 − p x ) ans = \sum \prod_{x\in tree} p_x \prod_{x\ not\in tree} (1-p_x) ans=∑x∈tree∏pxx not∈tree∏(1−px)
qwq而根据矩阵树定理,我们可以求出来所有生成树的边权乘积的和,也就是前一部分。
现在我们考虑应该怎么优化第二部分。
qwq
我们经过推理能发现,我们可以用总的除去在生成树里面的求出来不在生成树里面的。
也就是说
∏
x
n
o
t
∈
t
r
e
e
(
1
−
p
x
)
=
∏
(
1
−
p
i
)
∏
x
∈
t
r
e
e
(
1
−
p
j
)
\prod_{x\ not \in tree} (1-p_x)= \frac{\prod (1-p_i)}{\prod_{x\in tree} (1-p_j)}
x not∈tree∏(1−px)=∏x∈tree(1−pj)∏(1−pi)
我们带回原柿,然后把 ∏ p i \prod p_i ∏pi提出来
a n s = ∏ p x × ∑ ∏ x ∈ t r e e p x 1 − p x ans = \prod p_x \times \sum \prod_{x \in tree} \frac{p_x}{1-p_x} ans=∏px×∑x∈tree∏1−pxpx
那么现在,对于后面那一项,我们只需要把所有的边都设成权值是
∏
x
∈
t
r
e
e
p
x
1
−
p
x
\prod_{x \in tree} \frac{p_x}{1-p_x}
∏x∈tree1−pxpx
然后每个
d
[
i
]
d[i]
d[i]表示与他连接的所有边权的和。
直接跑矩阵树定理就能求出来 s u m sum sum啦,然后直接用一开始求的 ∏ p x \prod p_x ∏px,一减就OK了
但是这里有一个需要注意的地方就是当 p x p_x px等于 1 1 1的时候,我们应该将他的权值设成 1 − e p s 1-eps 1−eps
因为当 p p p等于1的时候, 1 1 − p − > i n f \frac{1}{1-p} -> inf 1−p1−>inf
然后有因为 1 e p s − > i n f \frac{1}{eps}->inf eps1−>inf
所以 p = 1 − e p s p=1-eps p=1−eps
然后弄完权值直接跑矩阵树定理就好
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define mk make_pair
#define ll long long
#include<ctime>
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
const int maxn = 110;
const double eps = 1e-6;
double a[maxn][maxn];
double d[maxn];
int n;
double ans=1;
void gauss()
{
int k=1;
for (int i=1;i<=n;i++)
{
int now = k;
while(now<=n && fabs(a[now][i])<=eps) now++;
if (now==n+1) continue;
for (int j=1;j<=n+1;j++) swap(a[now][j],a[k][j]);
for (int j=1;j<=n;j++)
{
if (j!=k)
{
double t = a[j][i]/a[k][i];
for (int p=1;p<=n+1;p++) a[j][p]-=t*a[k][p];
}
}
++k;
}
for (int i=1;i<=n;i++)
ans=ans*a[i][i];
}
double ymh=1;
int main()
{
n=read();
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
{
double x;
scanf("%lf",&x);
if (x==1) x = 1-eps;
if (i<j) ymh=ymh*(1-x);
x=x/(1-x);
a[i][j]=-x;
d[i]+=x;
//d[j]+=x;
}
for (int i=1;i<=n;i++) a[i][i]=d[i];
gauss();
printf("%.5lf",ans*ymh);
return 0;
}