码迷,mamicode.com
首页 > 其他好文 > 详细

[SDOI2014]重建

时间:2021-02-01 12:20:02      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:一个   printf   class   rip   link   mat   生成   答案   isp   

Description

一个 \(n\) 个点的图 \(G\),每两个点之间都有一个概率 \(p_{i,j}\) 存在一条边。求存在生成树的概率。

Solution

对于一个特定的生成树 \(T\),其边集为 \(E\),那么生成它的概率就是

\[\prod_{e\in E} p_e \prod_{e‘\notin E} (1-p_{e‘}) \]

即出现树边的概率积乘上不出现非树边的概率积。那么所有生成树的概率就是

\[\sum_{T} \prod_{e\in E} p_e \prod_{e‘\notin E} (1-p_{e‘}) \]

但是这并不能直接套 Matrix-tree 。考虑到 Matrix-tree 求的是所有生成树的边权积之和,所以需要想办法将后面的式子化成边权积。不难发现,如果把边权设成 \(\frac{p_e}{1-p_e}\) 就能很好的解决这个问题。答案即为

\[\prod_{e} (1-p_e)\sum_{T} \prod_{e\in E} \frac{p_e}{1-p_e} \]

还有一个问题,对于一条边,其出现的概率可能是 1。这就直接导致了分母为 0,除法会出问题。一开始想的是有没有什么做法可以求给定确定边的生成树个数,然后后面放弃了……转而回来想先前的做法。主要问题在于不能除 0,然后我非常灵性地对所有数加了一个 \(eps=10^{-10}\) ……竟一发过了。

复杂度 \(O(n^3)\)

#include<stdio.h>
#define N 53
#define eps 1e-10

int n;
double a[N][N];
int main(){
	scanf("%d",&n);
	double ans=1;
	for(int i=1;i<=n;i++)
    	for(int j=1;j<=n;j++){
        	double x;
        	scanf("%lf",&x);
        	x+=eps;
        	if(i!=j) a[i][j]=-x/(1-x),a[i][i]+=x/(1-x);
        	if(i<j) ans*=(1-x);
        }
	for(int i=2;i<=n;i++){
    	for(int j=i+1;j<=n;j++){
        	double t=a[j][i]/a[i][i];
        	for(int k=i;k<=n;k++)
            	a[j][k]-=a[i][k]*t;
        }
    	ans*=a[i][i];
    }
	printf("%.4lf",ans);
}
/*
3
0 0.5 0.5
0.5 0 0.5
0.5 0.5 0
*/

[SDOI2014]重建

标签:一个   printf   class   rip   link   mat   生成   答案   isp   

原文地址:https://www.cnblogs.com/wwlwQWQ/p/14350365.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!