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

P3317 [SDOI2014]重建

etc color tree tchar long ostream += font sin

傳送門

變元矩陣樹定理:求所有生成樹的總邊積的和,行列式中 $A[i][i]$ 為總邊權和,$A[i][j]$ 為 $i,j$ 之間邊權相反數

這題顯然考慮這個東西

但是不能直接把邊權變成概率,還要考慮非樹邊出現的概率

就是說原本矩陣樹可以求 $\sum _{Tree}\prod _{e\in Tree}P[e]$

但是此題要求的是 $\sum _{Tree}\prod _{e\in Tree}P[e]\prod _{e\notin Tree}(1-P[e])$

考慮化一下上面那個式子:

$\sum _{Tree}\prod _{e\in Tree}P[e]\prod _{e\notin Tree}(1-P[e])$

$=\sum _{Tree}\prod _{e\in Tree}P[e]\frac{\prod _{e}(1-P[e])}{\prod _{e\in Tree}(1-P[e])}$

$=\prod _{e}(1-P[e])\sum _{Tree}\prod _{e\in Tree}\frac{P[e]}{(1-P[e])}$

然後就可以矩陣樹了

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using
namespace std; typedef long long ll; typedef double db; inline int read() { int x=0,f=1; char ch=getchar(); while(ch<0||ch>9) { if(ch==-) f=-1; ch=getchar(); } while(ch>=0&&ch<=9) { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; }
const int N=107; const db eps=1e-7; int n; db A[N][N],ans=1; db Gauss() { db res=1.0; for(int i=1;i<n;i++) { int tmp=i; for(int j=i+1;j<n;j++) if(fabs(A[tmp][i])<fabs(A[j][i])) tmp=j; if(tmp!=i) swap(A[tmp],A[i]),res=-res; for(int j=i+1;j<n;j++) { db t=A[j][i]/A[i][i]; for(int k=i;k<n;k++) A[j][k]-=t*A[i][k]; } res*=A[i][i]; } return fabs(res); } int main() { n=read(); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) scanf("%lf",&A[i][j]); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) { db t= (1.0-A[i][j])<eps ? eps : 1.0-A[i][j];//防止分母為0 A[i][j]/=t; if(i<j) ans*=t; } for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(i!=j) A[i][i]+=A[i][j],A[i][j]*=-1; printf("%.10lf",ans*Gauss()); return 0; }

P3317 [SDOI2014]重建