SDOI2014 重建

题目链接:戳我

变元矩阵树定理,具体可以去看蒟蒻学习笔记中[树上问题]这一篇的整理QAQ

原式子为\(\sum_T\prod_{(u,v)\in T}p_{u,v}\prod_{(u,v)\notin T}(1-p_{u,v})\)

\(=\prod_{(u,v)\in G}(1-p_{u,v})\sum_T\prod_{(u,v)\in T}\frac{p_{u,v}}{1-p_{u,v}}\)

所以直接上变元矩阵树定理就可以了.

但是要注意我们中间涉及到除法操作,所以记得把概率为1的设置成为1-eps,概率为0的设置成eps

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define MAXN 110
#define eps 1e-8
using namespace std;
int n,p;
double all=1.0;
double a[MAXN][MAXN];
inline double solve()
{
    double cur_ans=1.0;
    for(int i=2;i<=n;i++)
    {
        int pos=i;
        for(int j=i+1;j<=n;j++)
            if(fabs(a[j][i])>fabs(a[pos][i]))
            pos=j;
        if(pos!=i) swap(a[i],a[pos]),cur_ans*=-1.0;
        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]-=t*a[i][k];
        }
    }
    for(int i=2;i<=n;i++)
    cur_ans*=a[i][i];
    return cur_ans;
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("ce.in","r",stdin);
    #endif
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            scanf("%lf",&a[i][j]);
            if(a[i][j]<eps) a[i][j]=eps;
            if(a[i][j]>1.0-eps) a[i][j]=1.0-eps;
            if(i<j) all*=(1.0-a[i][j]);
            a[i][j]=a[i][j]/(1.0-a[i][j]);
        }
    }
    /*
    for(int i=1;i<=n;i++)
    {
    for(int j=1;j<=n;j++)
        printf("%.3lf ",a[i][j]);
    printf("\n");
    }
    */
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            if(i!=j)
                a[i][i]-=a[i][j];
    for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++)
        a[i][j]=-a[i][j];
    //rintf("all=%.3lf\n",all);
    printf("%.6lf\n",     all*solve( )); 
    return 0;
}

posted @ 2019-05-30 07:25  风浔凌  阅读(125)  评论(0编辑  收藏  举报