P3317 [SDOI2014]重建

题目

P3317 [SDOI2014]重建

做法

我们都知道(其实我是刚知道的),矩阵树求的是:\(\sum\limits_{T}\prod\limits_{e \in T}p_e\)

而这题求的是:\(\sum\limits_{T}(\prod\limits_{e\in T}p_e \prod\limits_{e\notin T} (1-p_e))\)

通俗地将:枚举每个树,属于这个树边出现的概率\(×\)非树边出现的概率

\[\begin{aligned} &\sum\limits_{T}(\prod\limits_{e\in T}p_e \prod\limits_{e\notin T} (1-p_e))\\ &=\sum\limits_{T}(\prod\limits_{e\in T}p_e \frac{\prod_{e}(1-P_e)}{\prod_{e\in T}(1-P_e)})\\ &=\prod\limits_{e}(1-p_e)(\sum\limits_{T}\prod\limits_{e\in T}\frac{pe}{(1-pe)})\\ \end{aligned}\]

化成标准形式套模板就好了

My complete code

#include<cstdio>
#include<iostream>
#include<cmath>
using namespace std;
typedef int LL;
const double eps=1e-7;
const LL maxn=70;
LL n;
double ans=1.0;
double D[maxn][maxn],p[maxn][maxn];
inline double Solve(){
	double ret(1.0);
	LL N(n-1),tr(0);
	for(LL i=1;i<=N;++i){
		LL mx(i);
		for(LL j=i+1;j<=N;++j)
		    if(D[mx][i]<D[j][i])
		        mx=j;
		if(mx!=i)
		    swap(D[mx],D[i]),
			tr^=1;
		if(D[i][i]>-eps&&D[i][i]<eps)
		    return 0.0;
		for(LL j=i+1;j<=N;++j){
			double tmp=D[j][i]/D[i][i];
			for(LL k=i;k<=N;++k)
			    D[j][k]-=tmp*D[i][k];
		}
		ret=ret*D[i][i];
	}
	if(tr)
	    ret=-ret;
	return ret;
}
int main(){
	scanf("%d",&n);
	for(LL i=1;i<=n;++i){
		for(LL j=1;j<=n;++j){
			scanf("%lf",&D[i][j]);
		}
	}
	for(LL i=1;i<=n;++i){
		for(LL j=1;j<=n;++j){
			if(fabs(D[i][j])<eps)
			    D[i][j]=eps;
			else if(fabs(1.0-D[i][j])<eps)
			    D[i][j]=1.0-eps;
			if(j>i)
			    ans*=(1.0-D[i][j]);
			D[i][j]=D[i][j]/(1-D[i][j]);
		}
	}
	for(LL i=1;i<=n;++i){
		D[i][i]=0;
	    for(LL j=1;j<=n;++j)
	        if(i!=j)
	            D[i][i]+=D[i][j],
	            D[i][j]=-D[i][j];
	}
    ans*=Solve();
    printf("%.10lf\n",ans);
    return 0;
}/*
*/
posted @ 2019-01-14 14:35  y2823774827y  阅读(1522)  评论(0编辑  收藏  举报