• [NOI 2005]聪聪和可可


    Description

    题库链接

    一只猫和一只老鼠在一张 (n) 个节点和 (m) 条边的无向图上,初始位置不同。对于每一时刻,猫会先走,它走的方向为靠近老鼠的方向;若多个节点可选,则选字典序最小的那个。同时若走出这步后没有抓到老鼠,则可按同样方式再走一步;接着老鼠会等概率的停在原地或者随机走向一个相邻的节点。问抓到老鼠的期望时间。

    (1leq n,mleq 1000)

    Solution

    首先注意到这样一句话“若走出这步后没有抓到老鼠,则可按同样方式再走一步”,显然是能够保证猫一定能抓到老鼠。并且猫和老鼠两个所处位置的状态是具有层次性的。

    容易发现老鼠的移动是没有规律的,即是随机的。而猫的动作是有规律的。

    我们可以事先预处理出一个 (pre_{u,v}) 数组,表示猫在 (u) 处,老鼠在 (v) 处时,猫下一个选择要走的节点是哪一个,可以用 (n)(SPFA) 预处理出来,由于边数和点数是同阶的,复杂度可以得到保障。

    我们可以设出一个 (dp) 数组 (f_{u,v}) 表示猫在 (u) 处,老鼠在 (v) 处时期望走的时间为 (f_{u,v})

    首先显然当 (u=v) 时, (f_{u,v}=0) ;其次若 (pre_{u,v}=v) 即走出一步抓到老鼠或者 (pre_{pre_{u,v},v}=v) 即走出两步抓到老鼠, (f_{u,v}=1)

    这时剩下的情况就是老鼠会移动。

    由于猫会先走,猫移动之后老鼠再走;显然猫移动结束后停在的位置为 (pre_{pre_{u,v},v})

    设节点 (v) 以及和 (v) 相邻的节点的集合为 (mathbb{V}) ,节点 (v) 的度数为 (degree_v) 。显然答案就是 [f_{u,v}=frac{sumlimits_{xinmathbb{V}}f_{pre_{pre_{u,v},v},x}}{degree_v+1}+1]

    记忆化搜索实现。

    Code

    //It is made by Awson on 2018.2.24
    #include <bits/stdc++.h>
    #define LL long long
    #define dob complex<double>
    #define Abs(a) ((a) < 0 ? (-(a)) : (a))
    #define Max(a, b) ((a) > (b) ? (a) : (b))
    #define Min(a, b) ((a) < (b) ? (a) : (b))
    #define Swap(a, b) ((a) ^= (b), (b) ^= (a), (a) ^= (b))
    #define writeln(x) (write(x), putchar('
    '))
    #define lowbit(x) ((x)&(-(x)))
    using namespace std;
    const int N = 1000;
    void read(int &x) {
        char ch; bool flag = 0;
        for (ch = getchar(); !isdigit(ch) && ((flag |= (ch == '-')) || 1); ch = getchar());
        for (x = 0; isdigit(ch); x = (x<<1)+(x<<3)+ch-48, ch = getchar());
        x *= 1-2*flag;
    }
    void print(LL x) {if (x > 9) print(x/10); putchar(x%10+48); }
    void write(LL x) {if (x < 0) putchar('-'); print(Abs(x)); }
    
    int n, m, s, t, u, v;
    struct tt {int to, next; }edge[(N<<1)+5];
    int path[N+5], top, degree[N+5];
    int pre[N+5][N+5]; double f[N+5][N+5];
    queue<int>Q;
    int vis[N+5], dist[N+5];
    
    void add(int u, int v) {edge[++top].to = v, edge[top].next = path[u], path[u] = top, ++degree[u]; }
    void get_pre(int x) {
        memset(dist, 127/3, sizeof(dist)); dist[x] = 0, vis[x] = 1; Q.push(x);
        while (!Q.empty()) {
        int u = Q.front(); Q.pop(); vis[u] = 0;
        for (int i = path[u]; i; i = edge[i].next)
            if (dist[edge[i].to] > dist[u]+1) {
            dist[edge[i].to] = dist[u]+1;
            if (!vis[edge[i].to]) vis[edge[i].to] = 1, Q.push(edge[i].to);
            if (u == x) pre[x][edge[i].to] = edge[i].to; else pre[x][edge[i].to] = pre[x][u];
            }else if (dist[edge[i].to] == dist[u]+1 && pre[x][edge[i].to] > pre[x][u]) pre[x][edge[i].to] = pre[x][u];
        }
    }
    double dp(int s, int t) {
        if (s == t) return 0;
        int nex = pre[pre[s][t]][t];
        if (pre[s][t] == t || nex == t) return f[s][t] = 1;
        if (f[s][t] != 0) return f[s][t];
        double k = 1/(1.0*(degree[t]+1)); f[s][t] = 1+dp(nex, t)*k;
        for (int i = path[t]; i; i = edge[i].next) f[s][t] += k*dp(nex, edge[i].to);
        return f[s][t];
    }
    void work() {
        read(n), read(m); read(s); read(t);
        for (int i = 1; i <= m; i++) read(u), read(v), add(u, v), add(v, u);
        for (int i = 1; i <= n; i++) get_pre(i);
        printf("%.3lf
    ", dp(s, t));
    }
    int main() {
        work(); return 0;
    }
  • 相关阅读:
    hashids typescript lua 定义文件
    luarocks 私服搭建&简单使用
    dremio 21.1 UI 新变动
    localstack 试用
    iasqlengine 基础设施即数据
    apisix 提供的一些方便的openresty lua 模块
    citus ha 参考部署方案
    citus 一些不错的资料
    minio Error: Storage resources are insufficient for the read operation 问题参考解决
    citus 11.0 beta 发布
  • 原文地址:https://www.cnblogs.com/NaVi-Awson/p/8465730.html
Copyright © 2020-2023  润新知