zoukankan      html  css  js  c++  java
  • bzoj3143

    【bzoj3143】[Hnoi2013]游走

    题目描述

    一个无向连通图,顶点从1编号到N,边从1编号到M。 
    小Z在该图上进行随机游走,初始时小Z在1号顶点,每一步小Z以相等的概率随机选 择当前顶点的某条边,沿着这条边走到下一个顶点,获得等于这条边的编号的分数。当小Z 到达N号顶点时游走结束,总分为所有获得的分数之和。 
    现在,请你对这M条边进行编号,使得小Z获得的总分的期望值最小。

    输入

    第一行是正整数N和M,分别表示该图的顶点数 和边数,接下来M行每行是整数u,v(1≤u,v≤N),表示顶点u与顶点v之间存在一条边。 输入保证30%的数据满足N≤10,100%的数据满足2≤N≤500且是一个无向简单连通图。

    输出

    仅包含一个实数,表示最小的期望值,保留3位小数。

    样例输入

    3 3 
    2 3
    1 2
    1 3

    样例输出

    3.333

     

    sol:十分显然的是要让经过概率高的边权尽可能小,难点就在于求每条边被经过的概率

    令一个点 x 的度数为 Degx,那么对于一条边<U,V>,被经过的概率就是(经过点U的概率*1/Deg[U]+经过点V的概率*1/Deg[V])

    经过某个点的概率就是∑与它相连的点的概率/那个点的度数,这个显然是一个n个未知数,n个式子的一次方程组,可以用高斯消元求解

    Ps:经过1的概率要+1,经过n的概率是0,因为到了n是不会出来的

    // luogu-judger-enable-o2
    #include <bits/stdc++.h>
    using namespace std;
    typedef int ll;
    inline ll read()
    {
        ll s=0;
        bool f=0;
        char ch=' ';
        while(!isdigit(ch))
        {
            f|=(ch=='-'); ch=getchar();
        }
        while(isdigit(ch))
        {
            s=(s<<3)+(s<<1)+(ch^48); ch=getchar();
        }
        return (f)?(-s):(s);
    }
    #define R(x) x=read()
    inline void write(ll x)
    {
        if(x<0)
        {
            putchar('-'); x=-x;
        }
        if(x<10)
        {
            putchar(x+'0');    return;
        }
        write(x/10);
        putchar((x%10)+'0');
        return;
    }
    #define W(x) write(x),putchar(' ')
    #define Wl(x) write(x),putchar('
    ')
    const int N=505,M=500005;
    int n,m;
    int tot=0,Next[M],to[M],head[N],Deg[N];
    double a[N][N],b[N];
    struct Bian
    {
        int U,V;
        double Gl;
    }E[M];
    inline bool cmp_Gl(Bian p,Bian q)
    {
        return p.Gl<q.Gl;
    }
    inline void add(int x,int y)
    {
        Deg[x]++;
        Next[++tot]=head[x];
        to[tot]=y;
        head[x]=tot;
    }
    inline void Debug(int n)
    {
        int i,j;
        for(i=1;i<=n;i++)
        {
            for(j=1;j<=n;j++) printf("%.2lf ",a[i][j]);
            printf("%.2lf",b[i]);
            putchar('
    ');
        }
        putchar('
    ');
    }
    inline void Gauss(int n)
    {
        int i,j,k;
        double Div;
        for(i=1;i<=n;i++)
        {
            int Pos=i;
            for(j=i+1;j<=n;j++) if(fabs(a[Pos][i])<fabs(a[j][i])) Pos=j;
            if(Pos!=i)
            {
                swap(a[Pos],a[i]); swap(b[Pos],b[i]);
            }
            Div=a[i][i];
            for(j=i;j<=n;j++) a[i][j]/=Div; b[i]/=Div;
            for(j=1;j<=n;j++) if(j!=i)
            {
                double Div=a[j][i];
                for(k=i;k<=n;k++) a[j][k]-=Div*a[i][k];
                b[j]-=Div*b[i];
            }
    //        Debug(n);
        }
    }
    int main()
    {
        int i,j;
        R(n); R(m);
        for(i=1;i<=m;i++)
        {
            int x=read(),y=read();
            add(x,y); add(y,x);
            E[i].U=x; E[i].V=y;
        }
        for(i=1;i<n;i++)
        {
            a[i][i]=1.0;
            for(j=head[i];j;j=Next[j]) if(to[j]!=n)
            {
                a[i][to[j]]=-1.0/Deg[to[j]];
            }
            b[i]=(i==1)?1:0;
        }
        Gauss(n-1);
        for(i=1;i<=m;i++)
        {
            E[i].Gl=1.0*b[E[i].U]/Deg[E[i].U]+1.0*b[E[i].V]/Deg[E[i].V];
        }
        sort(E+1,E+m+1,cmp_Gl);
        double ans=0;
        for(i=1;i<=m;i++)
        {
            ans+=1.00*E[i].Gl*(m-i+1);
        }
        printf("%.3lf
    ",ans);
        return 0;
    }
    /*
    input
    3 3
    2 3
    1 2
    1 3
    output
    3.333
    */
    View Code
  • 相关阅读:
    Java实现自定义排序
    常用加密算法
    隐式传参
    mybatis-plus多租户的使用
    Python3.x基础学习-类--面向对象
    Python3.x基础学习-函数用法(四)
    Python3.x基础学习-函数用法(三)
    Python3.x基础学习-函数用法(二)
    功能测试经验汇总(--持续更新)
    Python3.x基础学习-函数用法(一)
  • 原文地址:https://www.cnblogs.com/gaojunonly1/p/10713610.html
Copyright © 2011-2022 走看看