正题
其实我们之前用图造树,求的都是
.
但是这题要我们求的是这个
我们发现少了什么。。。
但是少了的东西可以被表示为
所以,我们把这个东西带进原来的式子,就可以发现。
化简就可以得到
又因为后面东西可以直接得到,所以,将原来的边权变为跑行列式即可。
下面有几个小问题需要注意。
1.当为1时,我们需要给他减去一个极小的数,来保证不会除0.
2.我们求行列式的打法也需要改一改,变为先求出最大那一行,然后再不断与其他行相减,否则会有精度误差。
3.通常我们认为与0误差小于1e-8的数就是0, 接近1同理。
注意精度,否则你会被卡得很惨!!
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std;
int n;
const double eps=1e-8;
double d[55][55];
double last=1;
double temp=0;
double myabs(double x){
if(x<0) return -x;
return x;
}
double get_ans(int n){
double ans=1;
for(int j=1;j<=n;j++){
int mmax=j;
for(int i=j+1;i<=n;i++)
if(myabs(d[i][j])>myabs(d[mmax][j])) mmax=i;
if(mmax!=j) for(int i=1;i<=n;i++) swap(d[mmax][i],d[j][i]);
for(int i=j+1;i<=n;i++){
temp=d[i][j]/d[j][j];
for(int k=j;k<=n;k++)
d[i][k]=(d[i][k]-temp*d[j][k]);
}
ans*=d[j][j];
}
return myabs(ans);
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
scanf("%lf",&d[i][j]);
if(i==j) continue;
if(d[i][j]>1-eps) d[i][j]-=eps;
if(i<j) last*=(1-d[i][j]);
d[i][j]/=(1-d[i][j]);
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(i!=j) d[i][i]+=d[i][j],d[i][j]=-d[i][j];
printf("%.10lf",last*get_ans(n-1));
}