题目描述

Griseo 是黄金庭园的团宠小画家,最近她又开始了她的创作。

由于 Griseo 画工强大,所以她只需要在画布(视为 n*m 的二维平面,坐标起始点为 1)的某处点上一笔,颜料就会依照 Griseo 的想法无尽扩散,颜料的扩散方式是这样的:

1、初始时颜料会向上扩散; 2、每个小时,颜料会根据 Griseo 的想法扩散 s[i] 的距离; 3、当该小时结束后,颜料将分裂成两部分,向左上角以及右上角移动(颜料必须走过 si 的距离才能向两边分裂);

Griseo 想知道在每个小时末颜料的覆盖范围,以此推测画作的模样。

输入

第一行包含三个整数 n 、 m 、 t ,代表画布大小(n 行 m 列)和颜料扩散时间; 第二行包含 t 个整数 s[i],代表第 i 个小时颜料扩散的距离; 第三行包含两个整数 x、y 代表颜料的初始位置。

输出

输出为一行,包含 t 个整数,第 i 个整数代表第 i 个小时末画布上颜料的覆盖范围。

题目分析

本题可以使用搜索算法来解决,每次搜索到一个点时,将该点的值更新为当前时间,然后分别向左上和右上搜索,并更新这两个点的值为当前时间加上 s[i]。搜索过程中,如果搜到的点已经被更新过,或者超出了画布边界,则直接跳过。

在搜索过程中,可以使用优先队列(堆)来优化搜索顺序,每次取出覆盖时间最早的点进行搜索。当堆为空时,说明所有点都已经搜索完毕,可以结束搜索。

代码实现

代码中使用了一个结构体 Point 来存储每个点的坐标和覆盖时间,使用了一个数组 visited 来记录每个点是否已经被搜索过。

#include <iostream>
#include <queue>
#include <vector>

using namespace std;

struct Point {
    int x, y, time;
};

bool operator<(const Point& a, const Point& b) {
    return a.time > b.time;
}

int main() {
    int n, m, t;
    cin >> n >> m >> t;
    vector<int> s(t);
    for (int i = 0; i < t; ++i) {
        cin >> s[i];
    }
    int x, y;
    cin >> x >> y;

    vector<vector<int>> visited(n + 1, vector<int>(m + 1, -1));
    priority_queue<Point> pq;
    pq.push({x, y, 0});
    visited[x][y] = 0;

    vector<int> result(t, 0);
    for (int i = 0; i < t; ++i) {
        while (!pq.empty() && pq.top().time <= i) {
            Point cur = pq.top();
            pq.pop();

            // 向上扩散
            for (int j = cur.y + 1; j <= cur.y + s[i]; ++j) {
                if (j <= n && visited[cur.x][j] == -1) {
                    visited[cur.x][j] = i + 1;
                    pq.push({cur.x, j, i + 1});
                }
            }

            // 向左上和右上扩散
            if (cur.x - s[i] >= 1 && cur.y - s[i] >= 1) {
                if (visited[cur.x - s[i]][cur.y - s[i]] == -1) {
                    visited[cur.x - s[i]][cur.y - s[i]] = i + 1 + s[i];
                    pq.push({cur.x - s[i], cur.y - s[i], i + 1 + s[i]});
                }
            }
            if (cur.x + s[i] <= n && cur.y - s[i] >= 1) {
                if (visited[cur.x + s[i]][cur.y - s[i]] == -1) {
                    visited[cur.x + s[i]][cur.y - s[i]] = i + 1 + s[i];
                    pq.push({cur.x + s[i], cur.y - s[i], i + 1 + s[i]});
                }
            }
        }

        // 计算覆盖范围
        int count = 0;
        for (int j = 1; j <= n; ++j) {
            for (int k = 1; k <= m; ++k) {
                if (visited[j][k] <= i + 1) {
                    ++count;
                }
            }
        }
        result[i] = count;
    }

    for (int i = 0; i < t; ++i) {
        cout << result[i] << ' ';
    }
    cout << endl;

    return 0;
}

时间复杂度

由于最坏情况下每个点都需要被搜索一次,时间复杂度为 O(nmlog(nm))。空间复杂度为 O(nm)。

Griseo 的画作:使用分枝限界法求解颜料扩散范围

原文地址: https://www.cveoy.top/t/topic/oczH 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录