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;
}
原文地址:https://www.cnblogs.com/reverymoon/p/9498038.html