[SDOI2014]重建
题目描述
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 < N < =50
数据保证答案非零时,答案不小于10^-4
首先矩阵树定理的度数矩阵记录的是每个点的边权和,邻接矩阵记录的是边权,求的则是所有生成树的边权乘积和
一棵生成树的概率就是所有存在的边的存在概率乘不存在的边的不存在概率
我们把每个边权设为$\frac{p(i,j)}{1-p(i,j)}$
然后求出生成树概率后乘以所有$1-p(i,j)$
如果没有选的边就会乘1-p(i,j)
如果有选的边就等价于
$\frac{p(i,j)}{1-p(i,j)}*(1-p(i,j))$
$p(i,j)$
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 int n; 8 double eps=1e-9; 9 double sum,ans,a[51][51]; 10 void guass() 11 { 12 int i,j,now,k; 13 n--; 14 ans=1; 15 for (i=1; i<=n; i++) 16 { 17 now=i; 18 for (j=i+1; j<=n; j++) 19 { 20 if (fabs(a[j][i])>fabs(a[now][i])) now=j; 21 } 22 if (now!=i) 23 for (j=i; j<=n; j++) 24 swap(a[i][j],a[now][j]),ans=-ans; 25 for (j=i+1; j<=n; j++) 26 { 27 double t=a[j][i]/a[i][i]; 28 for (k=i; k<=n; k++) 29 { 30 a[j][k]-=t*a[i][k]; 31 } 32 } 33 } 34 for (i=1; i<=n; i++) 35 ans=ans*a[i][i]; 36 ans=fabs(ans); 37 } 38 int main() 39 { 40 int i,j; 41 cin>>n; 42 sum=1; 43 for (i=1; i<=n; i++) 44 { 45 for (j=1; j<=n; j++) 46 { 47 scanf("%lf",&a[i][j]); 48 if (i==j) continue; 49 double tmp=1-a[i][j]; 50 if (tmp<=eps) tmp=eps; 51 if (i<j) 52 sum*=tmp; 53 a[i][j]/=tmp; 54 } 55 } 56 for (i=1; i<=n; i++) 57 { 58 for (j=1; j<=n; j++) 59 if (j!=i) 60 { 61 a[i][i]+=a[i][j]; 62 a[i][j]=-a[i][j]; 63 } 64 } 65 guass(); 66 ans=sum*ans; 67 printf("%.10lf\n",ans); 68 }