zoukankan      html  css  js  c++  java
  • Bzoj3143 [Hnoi2013]游走

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 2816  Solved: 1207

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

    Sample Input

    3 3
    2 3
    1 2
    1 3

    Sample Output

    3.333

    HINT

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

    Source

    数学问题 数学期望 高斯消元+贪心

    使得总分期望值最小,显然需要求出每条边的期望被经过次数,然后给次数最多的边标上最小的编号。

    一条边(x,y)的期望被经过次数等于点x的经过次数*从x到y的概率(1/出度) +点y的经过次数*从y到x的概率

    那么现在只需要求每个点的经过次数就可以了

    $P[x]=sum_{i=1,i!=x}^{n}P[i]*k[i][x]$  $k[i][x]=1.0/outdeg[i]$

    特别地,P[1]等于那一串再加一个1,因为点1一开始就被经过了一次

    第n个点进去就出不来,可以忽视

    ↑忽视不代表可以直接删掉第n行第n列,因为其他向量的计算还要用到这部分。

    第57、58行算出度,调用了先前的u和v,WAWAWA

     1 /*by SilverN*/
     2 #include<algorithm>
     3 #include<iostream>
     4 #include<cstring>
     5 #include<cstdio>
     6 #include<cmath>
     7 #include<vector>
     8 using namespace std;
     9 const int mxn=505;
    10 int read(){
    11     int x=0,f=1;char ch=getchar();
    12     while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    13     while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
    14     return x*f;
    15 }
    16 struct edge{
    17     int x,y;
    18 }e[mxn*mxn];
    19 int n,m;
    20 double ans=0;
    21 double f[mxn][mxn];
    22 void Gauss(){
    23     int i,j,k;
    24     for(i=1;i<=n;i++){
    25         int p=i;
    26         for(j=i+1;j<=n;j++)if(fabs(f[j][i])>fabs(f[p][i]))p=j;
    27         if(p!=i)
    28             for(j=i;j<=n+1;j++)swap(f[p][j],f[i][j]);
    29         for(j=i+1;j<=n;j++){
    30             double x=f[j][i]/f[i][i];
    31             for(k=i;k<=n+1;k++){
    32                 f[j][k]-=f[i][k]*x;
    33             }
    34         }
    35     }
    36     for(i=n;i;i--){
    37         for(j=i+1;j<=n;j++)
    38             f[i][n+1]-=f[i][j]*f[j][n+1];
    39         f[i][n+1]/=f[i][i]; 
    40 //        printf("i:%.3f
    ",f[i][n+1]);
    41     }
    42     return;
    43 }
    44 double k[mxn][mxn];//点到点转移的概率 
    45 double g[mxn*mxn];//边被使用的期望次数 
    46 int out[mxn];//出度
    47 int cmp(double a,double b){return a>b;}
    48 int main(){
    49     int i,j,u,v;
    50     n=read();m=read();
    51     for(i=1;i<=m;i++){
    52         u=read();v=read();
    53         e[i].x=u;e[i].y=v;
    54         ++out[v];++out[u];
    55     }
    56     for(i=1;i<=m;i++){
    57         k[e[i].x][e[i].y]+=(double)1/out[e[i].x];
    58         k[e[i].y][e[i].x]+=(double)1/out[e[i].y];
    59     }
    60     f[1][n+1]=-1;f[n][n]=1;f[n][n+1]=0;
    61     for(i=1;i<n;i++){
    62         for(j=1;j<=n;j++){
    63             f[i][j]=k[j][i];
    64         }
    65         f[i][i]-=1;
    66     }
    67 /*    for(i=1;i<=n;i++){
    68         for(j=1;j<=n+1;j++)
    69             printf("%.3f  ",f[i][j]);
    70         printf("
    ");
    71     }*/
    72     Gauss();
    73     for(i=1;i<=m;i++){
    74         g[i]=f[e[i].x][n+1]/out[e[i].x]+f[e[i].y][n+1]/out[e[i].y];
    75     }
    76     sort(g+1,g+m+1,cmp);
    77     for(i=1;i<=m;i++)ans+=g[i]*i;
    78     printf("%.3f
    ",ans);
    79     return 0;
    80 }
  • 相关阅读:
    写代码注意了,打死都不要用 User 这个单词
    图解 Java 垃圾回收机制,写得非常好!
    Spring的核心模块解析
    单点登录终极方案之 CAS 应用及原理
    重磅!!Redis 6.0.0 已发布,有史以来改变最大的版本
    linux中$与()的一点使用疑惑解释
    mysql 行锁一则
    mysql: you can't specify target table 问题解决
    mysql update中需要根据条件列更新写法update case
    mysql depended_query 优化案例一则
  • 原文地址:https://www.cnblogs.com/SilverNebula/p/6606467.html
Copyright © 2011-2022 走看看