• Luogu 4206 [NOI2005]聪聪与可可


    BZOJ 1415

    简单期望 + 记忆化搜索。

    发现聪聪每一步走向的地方是在可可的所在位置确定时是确定的,设$nxt_{x, y}$表示聪聪在$x$,可可在$y$时聪聪下一步会走到哪里,我们先预处理出这个$nxt$。

    为了预处理$nxt$,我们还需要先预处理一个$d_{x, y}$表示$x$到$y$的最短距离,因为所有边的边权相同,所以我们第一次广搜到一个点的时候就是到这个点的最短路。

    假如$d_{x, z} == d_{y, z} + 1$,$dis(x, y) == 1$,那么$z$就是$x$到$y$最短路上的一个点,用它更新$nxt_{x, y}$即可。

    我们设$f_{x, y}$ 表示聪聪在$x$,可可在$y$时抓到可可的期望步数,显然有:

      $f_{x, y} == 0$  $(x == y)$

      $f_{x, y} == 1$  $(nxt_{x, y} == y)$  或者 $(nxt_{nxt_{x, y}, y} == y)$

    而根据期望的性质,可可的随机行走可以表示成这个公式:

      $f_{x, y} = frac{sum _{z} f_{nxt_{nxt_{x, y}, y}, z}}{deg_y + 1} + 1$  $z == y$或者$z$可由$y$一步走到。 

    记忆化搜索实现。

    时间复杂度$O(n^2)$。

    Code:

    #include <cstdio>
    #include <cstring>
    #include <queue>
    using namespace std;
    typedef double db;
    
    const int N = 1005;
    const int inf = 0x3f3f3f3f;
    
    int n, m, st, ed, d[N][N];
    int tot = 0, head[N], deg[N], nxt[N][N];
    db f[N][N];
    
    struct Edge {
        int to, nxt;
    } e[N << 1];
    
    inline void add(int from, int to) {
        e[++tot].to = to;
        e[tot].nxt = head[from];
        head[from] = tot;
    }
    
    inline void read(int &X) {
        X = 0; char ch = 0; int op = 1;
        for(; ch > '9'|| ch < '0'; ch = getchar())
            if(ch == '-') op = -1;
        for(; ch >= '0' && ch <= '9'; ch = getchar())
            X = (X << 3) + (X << 1) + ch - 48;
        X *= op;
    }
    
    inline void chkMin(int &x, int y) {
        if(y < x) x = y;
    } 
    
    queue <int> Q;
    inline void bfs(int fir, int *dis) {
        Q.push(fir);
        for(int i = 1; i <= n; i++) dis[i] = inf;
        dis[fir] = 0;
        
        for(; !Q.empty(); ) {
            int x = Q.front(); Q.pop();
            for(int i = head[x]; i; i = e[i].nxt) {
                int y = e[i].to;
                if(dis[y] == inf) {
                    dis[y] = dis[x] + 1;
                    Q.push(y);
                }
            }
        } 
    }
    
    db dfs(int x, int y) {
        if(f[x][y] != -1.0) return f[x][y];
        if(x == y) return f[x][y] = 0.0;
        if(nxt[x][y] == y) return f[x][y] = 1.0;
        if(nxt[nxt[x][y]][y] == y) return f[x][y] = 1.0;
        
        db res = 0;
        for(int i = head[y]; i; i = e[i].nxt) {
            int to = e[i].to;
            res += dfs(nxt[nxt[x][y]][y], to);
        }
        res += dfs(nxt[nxt[x][y]][y], y);
        
        return f[x][y]= res / (deg[y] + 1) + 1;
    }
    
    int main() {
        read(n), read(m), read(st), read(ed);
        for(int x, y, i = 1; i <= m; i++) {
            read(x), read(y);
            add(x, y), add(y, x);
            deg[x]++, deg[y]++; 
        }
        
        for(int i = 1; i <= n; i++) bfs(i, d[i]);
        
    /*    for(int i = 1; i <= n; i++, printf("
    "))
            for(int j = 1; j <= n; j++)
                printf("%d ", d[i][j]);    */
        
        memset(nxt, 0x3f, sizeof(nxt));
        for(int x = 1; x <= n; x++) {
            for(int i = head[x]; i; i = e[i].nxt) {
                int y = e[i].to;
                for(int k = 1; k <= n; k++)
                    if(d[x][k] == d[y][k] + 1)
                        chkMin(nxt[x][k], y);
            }
        }
        
    /*    for(int i = 1; i <= n; i++, printf("
    "))
            for(int j = 1; j <= n; j++)
                printf("%d ", nxt[i][j]);    */
        
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= n; j++)
                f[i][j] = -1.0;
        
        dfs(st, ed);
        
        printf("%.3f
    ", f[st][ed]);
        return 0;
    }
    View Code

      

  • 相关阅读:
    跟layout_weight说88,轻松搞定百分比布局
    跟闪退、程序崩溃说88
    程序的需求层次
    开博
    第十章 数组与集合 发牌程序 实例代码
    C#面向对象基础01
    winform form
    html
    C#语言基础02
    C#语言基础01
  • 原文地址:https://www.cnblogs.com/CzxingcHen/p/9740395.html
Copyright © 2020-2023  润新知