题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3534
题意:给定一个无向图,每条边有选择概率P;求选出的边恰是一棵生成树的概率。
首先,将A[i][j]从01变成这条边的概率,然后a[i][i]减去每条有i的边的概率,对此求n-1阶主子式的行列式,
可以得到:Σ(p[i]*p[i+1]*p[i+2]*...p[n-1])(p代表某棵树的集合中,这个集合里每条边选中的概率)
可是,这个概率只与树边有关,却无法保证没有非树边
我们重新考虑,令原先加入的a[i][j]变成(a[i][j]/(1-a[i][j])),再令tmp=(1-p[1])*(1-p[2])*...(1-p[m]),然后求行列式,最后选中的树边的因子,都是P[i],不选中的非树边的因子是(1-p[i]),于是问题完美解决。
1 #include<algorithm> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 #include<iostream> 6 double a[505][505]; 7 const double eps=1e-10; 8 int n; 9 int zero(double x){ 10 if (x<-eps) return -1; 11 else return x>eps; 12 } 13 double gauss(){ 14 double res=1; 15 for (int i=1;i<=n;i++){ 16 int k=i; 17 for (int j=i+1;j<=n;j++) if (fabs(a[j][i])>fabs(a[k][i])) k=j; 18 if (k!=i){ 19 for (int j=1;j<=n;j++) std::swap(a[i][j],a[k][j]); 20 } 21 for (int j=i+1;j<=n;j++){ 22 double tmp=a[j][i]/a[i][i]; 23 for (int k=i;k<=n;k++) 24 a[j][k]-=a[i][k]*tmp; 25 } 26 if (!zero(a[i][i])) return 0; 27 } 28 for (int i=1;i<=n;i++) res*=a[i][i]; 29 return std::fabs(res); 30 } 31 int main(){ 32 scanf("%d\n",&n); 33 double tm=1; 34 for (int i=1;i<=n;i++) 35 for (int j=1;j<=n;j++){ 36 scanf("%lf",&a[i][j]); 37 if (i==j) continue; 38 if (a[i][j]>1-eps) a[i][j]-=eps; 39 if (i<j) tm*=1-a[i][j]; 40 a[i][j]/=1-a[i][j]; 41 } 42 for (int i=1;i<=n;i++) 43 for (int j=1;j<=n;j++) 44 if (i!=j) 45 a[i][i]-=a[i][j]; 46 n--; 47 printf("%.10lf\n",gauss()*tm); 48 }
时间: 2024-11-15 16:54:23