• P3232 [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位小数。

    输入输出样例

    输入样例#1: 复制
    3 3
    2 3
    1 2
    1 3
    输出样例#1: 复制
    3.333

    说明

    边(1,2)编号为1,边(1,3)编号2,边(2,3)编号为3。

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    const int N=505;
    const int M=2e5+5;
    const double eps=1e-8;
    
    inline int read()
    {
        char c=getchar();int num=0;
        for(;!isdigit(c);c=getchar());
        for(;isdigit(c);c=getchar())
            num=num*10+c-'0';
        return num; 
    }
    
    int cmp(double a,double b)
    {
        if(fabs(a-b)<=eps)
            return 0;
        if(fabs(a)-fabs(b)>eps)
            return 1;
        return -1;
    }
    
    int n,m;
    double mat[N][N];    //Gauss Matrix
    
    int deg[N];
    double p[N];
    
    struct Edge
    {
        int u,v;
        double p;
        bool operator <(const Edge &a) const
        {
    //        return cmp(this->p,a.p)==-1;
            return p<a.p; 
        }
    }edge[M];
    
    void Gauss()
    {
        for(int i=1,p;i<=n;++i)
        {
            p=i;
            for(int j=i+1;j<=n;++j)
            {
                if(cmp(mat[p][i],mat[j][i])==-1)
                    p=j;
            }
            if(p!=i)
            {
                for(int j=i;j<=n+1;++j)
                {
                    swap(mat[p][j],mat[i][j]);
                }
            }
            for(int j=i+1;j<=n;++j)
            {
                double ratio=mat[j][i]/mat[i][i];
                for(int k=i;k<=n+1;++k)
                {
                    mat[j][k]-=mat[i][k]*ratio;
                }
            }
        }
        for(int i=n;i;--i)
        {
            for(int j=i+1;j<=n;++j)
            {
                mat[i][n+1]-=mat[i][j]*mat[j][n+1];
            }
            mat[i][n+1]/=mat[i][i];
        }
    }
    
    double ans;
    int main()
    {
        n=read(),m=read();
        for(int i=1,u,v;i<=m;++i)
        {
            u=read(),v=read();
            edge[i].u=u,edge[i].v=v;
            ++deg[u],++deg[v];
        }
        for(int i=1;i<=n;++i)
            mat[i][i]=-1;
        for(int i=1;i<=m;++i)
        {
            mat[edge[i].u][edge[i].v]+=1.0/deg[edge[i].v];
            mat[edge[i].v][edge[i].u]+=1.0/deg[edge[i].u];
        }
        for(int i=1;i<n;++i)
            mat[n][i]=0;
        mat[n][n]=1;
        mat[1][n+1]=-1;
    //    for(int i=1;i<=n;++i)
    //    {
    //        for(int j=1;j<=n+1;++j)
    //        {
    //            printf("%.3lf ",mat[i][j]);
    //        }
    //        puts("");
    //    }
        Gauss();
        for(int i=1;i<=m;++i)
        {
            edge[i].p=mat[edge[i].u][n+1]/(double)deg[edge[i].u]+mat[edge[i].v][n+1]/(double)deg[edge[i].v];
        }
        sort(edge+1,edge+m+1);
        for(int i=1;i<=m;++i)
        {
            ans+=edge[i].p*(m-i+1);
        }
        printf("%.3lf",ans);
        return 0;
    }
  • 相关阅读:
    高级程序设计语言学习2
    程序设计语言学习
    基于Android,对硬件、框架、API、操作系统、应用程序的理解
    Python_code_使用OpenCV库对图片实现数据增强
    Python_code_使用ImageFilter库对图片实现数据增强
    Python_code_实现贴图功能
    Python_code_使用OpenCV库实现对图像的_平移_旋转_缩放
    Python_code_七段数码管绘制实现_happy-new-year
    3_一幅图像,经过傅里叶变换后,将高频部分删除,再进行反变换,设想一下将会得到什么结果?
    2_图像处理中正交变换的目的是什么?图像变换主要用于那些方面?
  • 原文地址:https://www.cnblogs.com/lovewhy/p/9633521.html
Copyright © 2020-2023  润新知