luoguP4206 [NOI2005]聪聪与可可 期望概率DP

 

首先,分析一下这个猫和鼠

猫每局都可以追老鼠一步或者两步,但是除了最后的一步,肯定走两步快些....

既然猫走的步数总是比老鼠多,那么它们的距离在逐渐缩小(如果这题只能走一步反而不能做了...)

猫不知道老鼠下一步走哪里,猫走的时候依据的是老鼠当前的位置

 

明显,猫走的位置没有什么规律可言(即使有规律还是会预处理啊.....)

我们可以在$O(n^2 + nm)$的复杂度内预处理出$s(i, j)$表示猫在$i$,老鼠在$j$时,猫下一步的位置...

 

直接设$f(i, j)$表示猫在$i$,老鼠在$j$时猫吃到老鼠的期望步数

那么有$f(i, i) = 0$

并且$f(i, s(i, j)) = 1,f(i, s(s(i, j), j)) = 1 (i \neq j)$

其余情况下$f(i, j) = \sum\limits_{v = j | e(j, v)} \frac{f(s(s(i, j), j), v) + 1}{du[j] + 1}$

由于猫鼠距离减小,因此转移具有拓扑序

可以根据猫鼠距离排序转移,也可以直接$dfs$

由于$dfs$好写,因此这里选择$dfs$

复杂度$O(n^2 + nm)$

#include <cstdio>
#include <iostream>
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 sid 1005
#define eid 5005
#define ri register int

int n, m, s, t, cnp;
int cap[eid], nxt[eid], node[eid], q[eid];
int du[sid], dis[sid][sid], nx[sid][sid];
de f[sid][sid];

void adeg(int u, int v) {
    du[u] ++;
    nxt[++ cnp] = cap[u]; cap[u] = cnp; node[cnp] = v;
}

#define cur node[i]
void Pre() {
    for(ri u = 1; u <= n; u ++) {
        int fr = 1, to = 0;
        q[++ to] = u; dis[u][u] = 0;
        while(fr <= to) {
            int o = q[fr ++];
            for(ri i = cap[o]; i; i = nxt[i])
            if(dis[u][cur] == 1e5)
            dis[u][cur] = dis[u][o] + 1, q[++ to] = cur;
        }
    }
    for(ri u = 1; u <= n; u ++)
    for(ri v = 1; v <= n; v ++) {
        int w = 1e5;
        for(ri i = cap[u]; i; i = nxt[i])
        if(dis[cur][v] < w || (dis[cur][v] == w && nx[u][v] > cur))
        nx[u][v] = cur, w = dis[cur][v];
    }
}

de dfs(int a, int b) {
    if(f[a][b] != -1) return f[a][b];
    if(a == b) return f[a][b] = 0;
    int to = nx[a][b], toto = nx[to][b];
    if(to == b || toto == b) return f[a][b] = 1;
    f[a][b] = 0;
    for(int i = cap[b]; i; i = nxt[i])
    f[a][b] += (dfs(toto, cur) + 1) / (de)(du[b] + 1);
    f[a][b] += (dfs(toto, b) + 1) / (de)(du[b] + 1);
    return f[a][b];
}

int main() {
    n = read(); m = read();
    s = read(); t = read();
    for(ri i = 1; i <= m; i ++) {
        int u = read(), v = read();
        adeg(u, v); adeg(v, u);
    }

    for(ri i = 1; i <= n; i ++)
    for(ri j = 1; j <= n; j ++)
    dis[i][j] = 1e5, f[i][j] = -1;

    Pre();
    printf("%.3lf\n", dfs(s, t));
    return 0;
}

 

posted @ 2018-08-21 20:56  remoon  阅读(177)  评论(0编辑  收藏  举报