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

洛谷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\)\[ f(i,j)=1\quad \text{where}\ t_{i,j}=j\,\land\,t_{t_{i,j},j}=j \] 考虑转移。其实很简单,就是小猫追老鼠,老鼠随机乱跑(或者不动) \[ f(i,j) = 1 + \frac{1}{\operatorname{deg} (i) + 1} \left(f(t_{t_{i,j},j}, j) + \sum_{k,~(j,k)\in E}f(t_{t_{i,j},j},~k)\right) \] 记忆化搜索即可。

时间复杂度 \(\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 !
评论
  目录