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;
}

猜你喜欢

转载自www.cnblogs.com/lovewhy/p/9633521.html