zoukankan      html  css  js  c++  java
  • [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;
        
    }
  • 相关阅读:
    打造基于CentOS7的xfce最简工作环境
    Linux下C程序的编辑,编译和运行以及调试
    修正 XE6 TListView 上方 SearchBok 右边的清除钮显示
    TabControl 显示彩色的图示 (XE6 Firemonkey)
    TSwitch 中文简繁显示支持(XE6 Android)
    改变 TMemo 的背景颜色 (Firemonkey)
    修正 XE5 Android 键盘三个问题
    Delphi 收藏
    展示 Popup 的使用方法
    ListView 下拉更新 (支持 Android)
  • 原文地址:https://www.cnblogs.com/BriMon/p/9248514.html
Copyright © 2011-2022 走看看