1. 程式人生 > >[SDOI2014]重建

[SDOI2014]重建

等價 輸入輸出格式 != eps 一次 接下來 信息 font spa

題目描述

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

首先矩陣樹定理的度數矩陣記錄的是每個點的邊權和,鄰接矩陣記錄的是邊權,求的則是所有生成樹的邊權乘積和

一棵生成樹的概率就是所有存在的邊的存在概率乘不存在的邊的不存在概率

我們把每個邊權設為$\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 }

[SDOI2014]重建