嘘~ 正在从服务器偷取页面 . . .

洛谷P4206 [NOI2005] 聪聪与可可 题解


洛谷P4206 [NOI2005] 聪聪与可可 题解

题目链接:P4206 [NOI2005] 聪聪与可可

题意

在一个魔法森林里,住着一只聪明的小猫聪聪和一只可爱的小老鼠可可。虽然灰姑娘非常喜欢她们俩,但是,聪聪终究是一只猫,而可可终究是一只老鼠,同样不变的是,聪聪成天想着要吃掉可可。

一天,聪聪意外得到了一台非常有用的机器,据说是叫 GPS,对可可能准确的定位。有了这台机器,聪聪要吃可可就易如反掌了。于是,聪聪准备马上出发,去找可可。而可怜的可可还不知道大难即将临头,仍在森林里无忧无虑的玩耍。小兔子乖乖听到这件事,马上向灰姑娘报告。灰姑娘决定尽快阻止聪聪,拯救可可,可她不知道还有没有足够的时间。

整个森林可以认为是一个无向图,图中有 $N$ 个美丽的景点,景点从 $1$ 至 $N$ 编号。小动物们都只在景点休息、玩耍。在景点之间有一些路连接。

当聪聪得到 GPS 时,可可正在景点 $M$($M \le N$)处。以后的每个时间单位,可可都会选择去相邻的景点(可能有多个)中的一个或停留在原景点不动。而去这些地方所发生的概率是相等的。假设有 $P$ 个景点与景点 $M$ 相邻,它们分别是景点 $R$、景点 $S$、……、景点 $Q$,在时刻 $T$ 可可处在景点 $M$,则在 $(T+1)$ 时刻,可可有 $\frac{1}{P + 1}$ 的可能在景点 $R$,有 $\frac{1}{P + 1}$ 的可能在景点 $S$,……,有 $\frac{1}{P + 1}$ 的可能在景点 $Q$,还有$\frac{1}{P + 1}$的可能停在景点 $M$。

我们知道,聪聪是很聪明的,所以,当她在景点 $C$ 时,她会选一个更靠近可可的景点,如果这样的景点有多个,她会选一个标号最小的景点。由于聪聪太想吃掉可可了,如果走完第一步以后仍然没吃到可可,她还可以在本段时间内再向可可走近一步。

在每个时间单位,假设聪聪先走,可可后走。在某一时刻,若聪聪和可可位于同一个景点,则可怜的可可就被吃掉了。

灰姑娘想知道,平均情况下,聪聪几步就可能吃到可可。而你需要帮助灰姑娘尽快的找到答案。

输入格式

数据的第 1 行为两个整数 $N$ 和 $E$,以空格分隔,分别表示森林中的景点数和连接相邻景点的路的条数。

第 2 行包含两个整数 $C$ 和 $M$,以空格分隔,分别表示初始时聪聪和可可所在的景点的编号。

接下来 $E$ 行,每行两个整数,第 $i+2$ 行的两个整数 $A_i$ 和 $B_i$ 表示景点 $A_i$ 和景点 $B_i$ 之间有一条路。所有的路都是无向的,即:如果能从 A 走到 B,就可以从 B 走到 A。

输入保证任何两个景点之间不会有多于一条路直接相连,且聪聪和可可之间必有路直接或间接的相连。

输出格式

输出 1 个实数,四舍五入保留三位小数,表示平均多少个时间单位后聪聪会把可可吃掉。

数据范围

对于所有的数据,$1≤N,E≤1000$​。

因为 $|V|,|E| \le 1000$ ,所以可以乱搞预处理很多东西出来。

设 $d_{i,j}$ 为 $i,j$ 的最短距离,这个可以直接用 bfs 跑出来。

设 $t_{i,j}$ 表示小猫在 $i$ 、老鼠在 $j$ 时,小猫下一步应该往哪个点走,这个可以由 $d_{i,j}$ 快速得到。

然后设 $f(i,j)$ 表示小猫在 $i$ 、老鼠在 $j$ 时的期望步数。

边界 $f(i,i)=0$ 和

考虑转移。其实很简单,就是小猫追老鼠,老鼠随机乱跑(或者不动)

记忆化搜索即可。

时间复杂度 $\mathcal{O}(n^2)$

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
void up(int &x,int y) { x < y ? x = y : 0; }
void down(int &x,int y) { x > y ? x = y : 0; }
#define N ((int)(1e3 + 15))

int n, m, s, t, d[N][N], to[N][N];
vector<int> vec[N]; queue<int> q; double f[N][N];
double dp(int u, int v)
{
    if(u == v) return f[u][v] = 0;
    if(to[u][v] == v || to[to[u][v]][v] == v) return f[u][v] = 1;
    if(f[u][v] != 0.0) return f[u][v];
    for(int k : vec[v]) f[u][v] += dp(to[to[u][v]][v], k);
    f[u][v] += dp(to[to[u][v]][v], v);
    f[u][v] /= (double)vec[v].size() + 1; ++f[u][v];
    return f[u][v];
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    cin >> n >> m >> s >> t;
    for(int i = 1, u, v; i <= m; i++)
    {
        cin >> u >> v;
        vec[u].push_back(v); vec[v].push_back(u);
    }
    memset(d, -1, sizeof(d));
    for(int i = 1; i <= n; i++)
    {
        while(!q.empty()) q.pop();
        q.push(i); d[i][i] = 0;
        while(!q.empty())
        {
            int u = q.front(); q.pop();
            for(int v : vec[u])
                if(d[i][v] == -1) { d[i][v] = d[i][u] + 1, q.push(v); }
        }
    }
    memset(to, 0x3f, sizeof(to));
    for(int i = 1; i <= n; i++)
        for(int k : vec[i]) for(int j = 1; j <= n; j++)
            if(d[i][j] == d[k][j] + 1) down(to[i][j], k);
    cout << fixed << setprecision(3) << dp(s, t) << '\n';
    return 0;
}

参考文献

[1] https://www.luogu.com.cn/article/m7d61on0


题外话

没有图。


文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
  目录