题目描述
T国有N个城市,用若干双向道路连接。一对城市之间至多存在一条道路。
在一次洪水之后,一些道路受损无法通行。虽然已经有人开始调查道路的损毁情况,但直到现在几乎没有消息传回。
幸运的是,此前T国政府调查过每条道路的强度,现在他们希望只利用这些信息估计灾情。具体地,给定每条道路在洪水后仍能通行的概率,请计算仍能通行的道路恰有N-1条,且能联通所有城市的概率。
输入输出格式
输入格式:
输入的第一行包含整数N。
接下来N行,每行N个实数,第i+l行,列的数G[i][j]表示城市i与j之间仍有道路联通的概率。
输入保证G[i][j]=G[j][i],且G[i][j]=0;G[i][j]至多包含两位小数。
输出格式:
输出一个任意位数的实数表示答案。
你的答案与标准答案相对误差不超过10^(-4)即视为正确。
输入输出样例
输入样例#1:
3
0 0.5 0.5
0.5 0 0.5
0.5 0.5 0
输出样例#1:
0.375
说明
1 < N < =50
数据保证答案非零时,答案不小于10^-4
分析:
如果我们把基尔霍夫矩阵中的
A[i,i]
A
[
i
,
i
]
设为
i
i
相连的边的权值和,设为边
(i,j)
(
i
,
j
)
的权值相反数,那么跑出来的行列式的结果是每棵树的权值积的总和。假如我们把概率设为权值,结果就是
而答案是
根据考虑给 det d e t 乘上后面的东西,
那么假如我们把 A[i,j] A [ i , j ] 设为 p(i,j)(1−p(i,j)) p ( i , j ) ( 1 − p ( i , j ) ) ,再给行列式乘 ∏(i,j)(1−p(i,j)) ∏ ( i , j ) ( 1 − p ( i , j ) ) ,那么就是答案了。
当 p(i,j)=1 p ( i , j ) = 1 时,我们给 p(i,j)=1−10−12 p ( i , j ) = 1 − 10 − 12 就可以了。
代码:
#include <iostream>
#include <cstdio>
#include <cmath>
const int maxn=57;
using namespace std;
int n;
double a[maxn][maxn],b[maxn][maxn];
double ans;
double det(int n)
{
double ans=1;
for (int i=1;i<=n;i++)
{
for (int j=i+1;j<=n;j++)
{
double rate=a[j][i]/a[i][i];
for (int k=i;k<=n;k++)
{
a[j][k]-=rate*a[i][k];
}
}
ans*=a[i][i];
}
return ans;
}
int main()
{
scanf("%d",&n);
ans=1;
for (int i=1;i<=n;i++)
{
for (int j=1;j<=n;j++)
{
scanf("%lf",&b[i][j]);
if (b[i][j]==1) b[i][j]-=1e-12;
}
}
for (int i=1;i<=n;i++)
{
for (int j=1;j<=n;j++)
{
if (i>j) ans*=1-b[i][j];
if (i!=j)
{
a[i][j]=-b[i][j]/(1-b[i][j]);
a[i][i]-=a[i][j];
}
}
}
ans=abs(ans*det(n-1));
printf("%.8lf",ans);
}