zoukankan      html  css  js  c++  java
  • luoguP3232 [HNOI2013]游走 贪心 + 概率期望 + 高斯消元

    首先,题目中的无向简单连通图代表着没有自环,重边...

    总分的期望 = 每条边的期望之和...................每条边的期望又可以拆成$u o v$的期望和$v o u$的期望

    记$f[i]$表示$1 o n$的路径中,$i$的期望经过次数

    而$u o v$的期望只要知道$f[u], f[v]$就可以求出

    注意到,$f[i]$为每个时刻点在$i$的概率之和,即$sumlimits_{t =0}^{infty} p^i_t$

    那么,我们有$f[i] = sumlimits_{t = 0}^{infty} p^i_t = p^i_0 + sumlimits_{(i, v)} frac{1}{du[v]} * sumlimits_{t = 1}^{infty} p^v_t = p^i_0 + sumlimits_{(i, v)} frac{1}{du[v]} * f[v]$

    对于$f[1]$,有$p^1_0 = 1$

    对于其他点,有$p^i_0 = 0$

    列方程即可解决

    注意$n$号节点,一旦到了$n$号节点,游走结束

    因此,尽管$f[n]$在实际中为$1$,但是在方程中为了保证$n$号点不转移,令$f[n] = 0$

    计算边的期望时,$f[n]$同样不参与计算

    最后,求出了每条边的期望经过次数,希望总分期望尽量小

    当然是经过次数多的边给小编号了,贪心即可!

    复杂度$O(n^3)$

    注:$500^2 = 250000$,不知道什么时候才会记住

    注2:少用$luogu;ide$调试,莫名少头文件...

    #include <cmath>
    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    extern inline char gc() {
        static char RR[23456], *S = RR + 23333, *T = RR + 23333;
        if(S == T) fread(RR, 1, 23333, stdin), S = RR;
        return *S ++;
    }
    inline int read() {
        int p = 0, w = 1; char c = gc();
        while(c > '9' || c < '0') { if(c == '-') w = -1; c = gc(); }
        while(c >= '0' && c <= '9') p = p * 10 + c - '0', c = gc();
        return p * w;
    }
    
    #define de double
    #define ri register int
    #define sid 505
    #define eid 600005
    
    int n, m, cnp, du[sid];
    de ex[eid], f[sid][sid], g[sid];
    int cap[sid], nxt[eid], node[eid];
    
    inline void adeg(int u, int v) {
        du[u] ++;
        nxt[++ cnp] = cap[u]; cap[u] = cnp; node[cnp] = v;
    }
    
    void Guass() {
        for(ri i = 1; i <= n; i ++) {
            int p = i;
            for(ri j = i; j <= n; j ++) if(fabs(f[j][i]) > fabs(f[p][i])) p = j;
            swap(f[i], f[p]);
            for(ri j = i + 1; j <= n; j ++) {
                de t = f[j][i] / f[i][i];
                for(ri k = i; k <= n + 1; k ++)
                f[j][k] -= t * f[i][k];
            }
        }
        for(ri i = n; i >= 1; i --) {
            f[i][n + 1] = f[i][n + 1] / f[i][i];
            for(ri j = i - 1; j >= 1; j --)
            f[j][n + 1] -= f[i][n + 1] * f[j][i];
        }
        for(ri i = 1; i <= n; i ++) g[i] = f[i][n + 1];
    }
    
    int main() {
        n = read(); m = read();
        for(ri i = 1; i <= m; i ++) {
            int u = read(), v = read();
            adeg(u, v); adeg(v, u);
        }
        #define cur node[j]
        f[1][n + 1] = 1; f[n][n] = 1;
        for(ri i = 1; i < n; i ++) {
            f[i][i] = 1;
            for(ri j = cap[i]; j; j = nxt[j])
            f[i][cur] -= 1.0 / (de)(du[cur]); 
        } 
        Guass();
        int bnp = 0;
        for(ri i = 1; i <= n; i ++)
        for(ri j = cap[i]; j; j = nxt[j])
        ex[++ bnp] = g[i] / (de)du[i] + g[cur] / (de)du[cur];
        sort(ex + 1, ex + bnp + 1);
        de ans = 0;
        for(ri i = 1, j = 1; i <= bnp; i += 2, j ++) 
        ans += ex[i] * (m - j + 1);
        printf("%.3lf
    ", ans); 
        return 0;
    }
  • 相关阅读:
    窗口实训1
    课后练习----实现窗口的切换
    第五次实训作业继承
    课程总结
    999
    777777777777777777777
    7
    6
    5
    事件处理程序
  • 原文地址:https://www.cnblogs.com/reverymoon/p/9498038.html
Copyright © 2011-2022 走看看