• [HNOI2013][BZOJ3143] 游走


    题目描述

    一个无向连通图,顶点从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。


    题解

      期望dp。

      贪心地想,我们肯定要往那个期望到达次数最大的边赋最小的权值;

      所以问题转化成了求边的期望到达次数;

      我们发现一条边连着唯一的两个点,我们要知道边的期望,首先要知道到达每个点的期望次数;

      我们设f[i]表示第i个点的期望到达次数,即f[i] = ∑(f[to[i]] * deg[to[i]]) ,deg[i]表示一个点的度数;

      这样我们发现可以高斯消元解出;要注意的是1号点的期望还得加上1因为从他开始必定经过;

      然后求g[i],即边i的期望到达次数,g[i] = f[l[i]]/deg[l[i]] + f[r[i]]/deg[r[i]],l r表示这个边链接的两个点;

      要注意如果是n号点的话,就不用考虑,因为到了n点就不会继续游走了;

      然后就贪心地赋边权;


    Code

    #include <iostream>
    #include <cstdio>
    #include <cmath>
    #include <algorithm>
    using namespace std;
    #define eps 1e-8
    
    int n, m;
    struct edge
    {
        int from, to;
        int nxt;
    }ed[500010];
    int deg[505], head[505];
    int cnt;
    int fr[500010], tt[500010];
    inline void add(int x, int y){ed[++cnt] = (edge){x, y, head[x]};head[x] = cnt;}
    
    double g[250010];
    double a[505][505];
    double ans;
    
    inline void Gauss_()
    {
        for (register int i = 1 ; i < n ; i ++)
        {
            int pivot = i ;
            for (register int j = i + 1 ; j < n ; j ++)
            {
                if (fabs(a[j][i] - a[pivot][i]) <= eps) pivot = j;
            }
            if (pivot != i)
                for (register int j = 1 ; j <= n ; j ++)
                    swap(a[i][j], a[pivot][j]);
            for (register int j = n ; j >= i ; j --) a[i][j] /= a[i][i];
            for (register int j = 1 ; j < n ; j ++) 
                if (i != j) 
                    for (register int k = n ; k >= i ; k --)
                        a[j][k] -= a[j][i] * a[i][k];
        }
    }
    
    int main()
    {
        scanf("%d%d", &n, &m);
        for (register int i = 1; i <= m; i ++)
        {
            int x, y;
            scanf("%d%d", &x, &y);
            deg[x]++, deg[y]++;
            fr[i] = x, tt[i] = y;
            add(x, y);
            add(y, x);
        }
        
        a[1][n] = 1;
        for (register int i = 1; i < n; i ++)
        {
            a[i][i] = 1;
            for (register int j = head[i]; j; j = ed[j].nxt)
            {
                int to = ed[j].to ;
                if (to != n) a[i][to] = -1.0/deg[to];
            }
        }
        
        Gauss_();
            
        for (register int i = 1 ; i <= m ; i ++)
        {
            if (fr[i] != n )
                g[i] += a[fr[i]][n] * (1.0 / deg[fr[i]]) ;
            if (tt[i] != n)
                g[i] += a[tt[i]][n] * (1.0 / deg[tt[i]]);
        }
        
        sort(g + 1, g + 1 + m);
        for (register int i = 1 ; i <= m ; i ++) 
            ans += (m - i + 1) * 1.0 * g[i];
        printf("%.3lf", ans);
        
        return 0;
        
    }
  • 相关阅读:
    GitHub Actions 支持 "skip ci" 了
    自定义 ocelot 中间件输出自定义错误信息
    小心 Enum Parse 中的坑
    C# 实现一个基于值相等性比较的字典
    浅析 record 使用场景
    WARNING: IPv4 forwarding is disabled. Networking will not work.
    postgresql数据类型
    Illegal mix of collations (utf8mb4_unicode_ci,IMPLICIT) and (utf8_general_ci,COERCIBLE) for operation '='
    重放攻击及防御
    开放 HTTP API 接口签名验证!
  • 原文地址:https://www.cnblogs.com/BriMon/p/9248514.html
Copyright © 2020-2023  润新知