zoukankan      html  css  js  c++  java
  • bzoj3143 游走

    Description

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

    Input

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

    Output

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

    每个点i走到的期望次数x[i]=(i==1?1:0)+sigma(x[j]/o[j]) (j!=n , i到j有边)
    o[j]为j的度
    高斯消元解出每个x[i]
    边(a,b)走过的期望次数为(a==n?0:x[a]/o[a])+(b==n?0:x[b]/o[b])
    按边走过的次数从大到小排序并顺序编号
    #include<cstdio>
    #include<vector>
    #include<algorithm>
    int n,m,a,b;
    std::vector<int>es[512];
    double xs[512][512],ys[512],x[512],ans=0;
    int o[512];
    inline bool is0(double x){return x<1.0e-10&&x>-1.0e-10;}
    inline bool isn0(double x){return x>=1.0e-10||x<=-1.0e-10;}
    struct edge{
        int a,b;
        double v;
    }e[250000];
    int ep=0;
    bool operator<(edge a,edge b){
        return a.v>b.v;
    }
    int main(){
        scanf("%d%d",&n,&m);
        while(m--){
            scanf("%d%d",&a,&b);
            es[a].push_back(b);
            es[b].push_back(a);
            o[a]++;o[b]++;
            e[ep].a=a;e[ep++].b=b;
        }
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++)xs[i][j]=0;
            xs[i][i]=-1;
            for(int j=0;j<es[i].size();j++){
                int u=es[i][j];
                if(u!=n)xs[i][u]+=1.0/o[u];
            }
            ys[i]=0;
        }
        ys[1]=-1;
        for(int t=1;t<=n;t++){
            if(is0(xs[t][t]))
            for(int i=t+1;i<=n;i++){
                if(isn0(xs[i][t])){
                    for(int j=t;j<=n;j++){double v=xs[i][j];xs[i][j]=xs[t][j];xs[t][j]=v;}
                    double v=ys[i];ys[i]=ys[t];ys[t]=v;
                }
            }
            double c=1.0/xs[t][t];
            for(int i=t;i<=n;i++)xs[t][i]*=c;
            ys[t]*=c;
            for(int i=t+1;i<=n;i++){
                if(isn0(xs[i][t])){
                    double k=xs[i][t];
                    for(int j=t;j<=n;j++){
                        xs[i][j]-=xs[t][j]*k;
                    }
                    ys[i]-=ys[t]*k;
                }
            }
        }
        for(int t=n;t;t--){
            for(int i=t+1;i<=n;i++){
                ys[t]-=xs[t][i]*x[i];
            }
            x[t]=ys[t];
        }
        for(int i=0;i<ep;i++){
            e[i].v=0;
            if(e[i].a!=n)e[i].v+=x[e[i].a]/o[e[i].a];
            if(e[i].b!=n)e[i].v+=x[e[i].b]/o[e[i].b];
        }
        std::sort(e,e+ep);
        for(int i=0;i<ep;i++)ans+=e[i].v*(i+1);
        printf("%.3lf
    ",ans);
        return 0;
    }
  • 相关阅读:
    [BZOJ1666][Usaco2006 Oct]Another Cow Number Game 奶牛的数字游戏
    [BZOJ1692][Usaco2007 Dec]队列变换
    [BZOJ1599][Usaco2008 Oct]笨重的石子
    [BZOJ1603][Usaco2008 Oct]打谷机
    [BZOJ1614][Usaco2007 Jan]Telephone Lines架设电话线
    [BZOJ1617][Usaco2008 Mar]River Crossing渡河问题
    [BZOJ1612][Usaco2008 Jan]Cow Contest奶牛的比赛
    [BZOJ1600][Usaco2008 Oct]建造栅栏
    [BZOJ1230][Usaco2008 Nov]lites 开关灯
    hdu 2199 Can you solve this equation? 二分
  • 原文地址:https://www.cnblogs.com/ccz181078/p/5234818.html
Copyright © 2011-2022 走看看