zoukankan      html  css  js  c++  java
  • bzoj4637: 期望

    Description

    在米国有一所大学,名叫万国歌剧与信息大学(UniversalOperaandInformaticasUniversity)。简称UOI大学。UO
    I大学的建筑与道路分布很有趣,每对建筑之间有且仅有一条直接或者间接的路径相连,更加明确的说,就是成树
    形分布。其实在设计时,对于大学的N个建筑,总共有M条道路可以修建,每条道路都有一个距离值Disti和一个美
    学值Valuei。一个设计方案的距离值和美学值定义为该设计方案内包含的道路的距离值与美学值之和。投资方的要
    求只有设计方案的距离值最小。大神出于对树的喜爱所以决定设计方案必须是一棵树。因为要参加UOI,所以当时
    大神就急急忙忙地随机选择了一个合法的方案。但其实存在很多合法的方案,假设每种设计方案取的概率是均等的
    ,那么设计方案的美学值期望是多少?

    Input

    第一行两个整数,N和M,意义如上所述。
    第二行到第M+1行,每行4个整数,Xi,Yi,Disti,Valuei,分别表示这条道路连接的
    两个建筑的编号,距离值以及美学值。
    输入保证至少有一种合法方案。
    100%的数据保证N<=10000M<=200000
    100%的数据保证距离值相同的道路数小于30,同时不保证没有重边。

    Output

     一行一个整数,即满足总道路长度最小的情况下,设计方案的美学值期望。要求保留5位小数

    按边权升序加边同时缩点,忽略缩点产生的自环,对同一权值且 加入此权值的边后在同个联通块内 的一组边,用矩阵树定理计算出生成树个数以及删去每条边后的生成树个数,于是可得一条边在最小生成树中的概率,统计答案。似乎要用long double才能过,但计算行列式时无论用long double还是模意义下的整数计算都能过。

    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    typedef long double ld;
    #define double ld
    int _(){
        int x=0,c=getchar(),f=1;
        while(c<48)c=='-'&&(f=-1),c=getchar();
        while(c>47)x=x*10+c-48,c=getchar();
        return x*f;
    }
    int es[2007],enx[2007],e0[2007],ep=2,ev[2007];
    struct edge{
        int a,b,c,d;
        void init(){
            a=_();b=_();c=_();d=_();
        }
        void adde(){
            es[ep]=b;enx[ep]=e0[a];ev[ep]=d;e0[a]=ep++;
            es[ep]=a;enx[ep]=e0[b];ev[ep]=d;e0[b]=ep++;
        }
    }e[200007];
    bool operator<(edge a,edge b){
        return a.c<b.c;
    }
    double ans=0;
    int n,m,f[100007],id[100007],idp=0,idt[100007],tk=0,ed[100007],ID[1007],IDP;
    int v[33][33],v1,ee[2007][3],eep,os[2007][2],op=0;
    int get(int x){
        int a=x,c;
        while(x!=f[x])x=f[x];
        while(x!=f[a])c=f[a],f[a]=x,a=c;
        return x;
    }
    void gid(int x){
        if(idt[x]!=tk)idt[x]=tk,id[x]=++idp;
    }
    void dfs(int w){
        if(ed[w]!=tk)ed[w]=tk,ID[w]=++IDP;
        for(int i=e0[w],u;i;i=enx[i]){
            u=es[i];
            if(ed[u]!=tk)dfs(u);
            if(ID[w]<ID[u]){
                ++v[ID[w]][ID[w]];
                ++v[ID[u]][ID[u]];
                --v[ID[w]][ID[u]];
                --v[ID[u]][ID[w]];
                ee[eep][0]=ID[w];
                ee[eep][1]=ID[u];
                ee[eep++][2]=ev[i];
            }
        }
    }
    const double _0=1e-9;
    double solve(int n){
        static double a[33][33];
        double s=1;
        for(int i=1;i<=n;++i)
            for(int j=1;j<=n;++j)
                a[i][j]=v[i][j];
        for(int i=1;i<=n;++i){
            if(fabs(a[i][i])<_0){
                int t=i;
                for(int j=i+1;j<=n;++j)if(fabs(a[j][i])>fabs(a[t][i]))t=j;
                if(fabs(a[t][i])<_0)return 0;
                for(int j=i;j<=n;++j)swap(a[i][j],a[t][j]);
            }
            for(int j=i+1;j<=n;++j)if(a[j][i]){
                double x=a[j][i]/a[i][i];
                for(int k=i;k<=n;++k)a[j][k]-=x*a[i][k];
            }
        }
        for(int i=1;i<=n;++i)s*=a[i][i];
        return s;
    }
    void chk(int x){
        if(ed[x]==tk)return;
        IDP=0;++tk;eep=0;
        dfs(x);
        double v0=solve(IDP-1);
        for(int i=0;i<eep;++i){
            int x=ee[i][0],y=ee[i][1];
            --v[x][x],--v[y][y],++v[x][y],++v[y][x];
            double v1=v0-solve(IDP-1);
            ans+=v1/v0*ee[i][2];
            ++v[x][x],++v[y][y],--v[x][y],--v[y][x];
        }
        for(int i=1;i<=IDP;++i){
            for(int j=1;j<=IDP;++j)v[i][j]=0;
        }
    }
    int main(){
        n=_();m=_();
        for(int i=1;i<=n;++i)f[i]=i;
        for(int i=0;i<m;++i)e[i].init();
        std::sort(e,e+m);
        for(int i=0,j=0;i<m;){
            for(++tk,idp=0;j<m&&e[i].c==e[j].c;++j);
            for(int k=i;k<j;++k){
                int x=get(e[k].a),y=get(e[k].b);
                if(x==y){
                    e[k].a=-1;
                    continue;
                }
                os[op][0]=e[k].a;os[op++][1]=e[k].b;
                gid(x);gid(y);
                e[k].a=id[x];
                e[k].b=id[y];
                e[k].adde();
            }
            while(op)--op,f[get(os[op][0])]=get(os[op][1]);
            for(;i<j;++i)if(~e[i].a){
                chk(e[i].a);
                chk(e[i].b);
            }
            for(int t=1;t<=idp;++t)e0[t]=0;
            ep=2;
        }
        printf("%.5Lf",ans);
        return 0;
    }
  • 相关阅读:
    Ubuntu上安装Redis
    Unity Shader中将指定颜色过滤成透明
    用Python发送邮件
    Flask搭建简单的服务器
    SQLServer 中All、Any和Some用法与区别
    Linux探秘之用户态与内核态
    MTDDL 美团点评分布式数据访问层中间件
    基础数据结构 例:栈、队列、链表、数据、字典、树、等
    二叉树、红黑树、B&B+树数据结构
    CPU,GPU,高速缓存cache,内存RAM,虚拟内存VM,磁盘ROM,磁盘缓存之间的关系
  • 原文地址:https://www.cnblogs.com/ccz181078/p/6171360.html
Copyright © 2011-2022 走看看