Griseo 的画作:颜料扩散范围 - 分支限界法求解

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 个小时末画布上颜料的覆盖范围。

分析

本题可以使用分支限界法求解,每个状态可以表示为颜料某时刻的覆盖范围,每次扩散后分裂成两个子状态,即左上角和右上角两个方向。

为了方便起见,可以将每个点表示为一个状态,即颜料覆盖该点的时刻,初始化为 -1。然后从起点开始扩散,将覆盖时间赋为 0。之后每次扩散时,对于每个被扩散到的点,计算左上角和右上角的状态,并进行剪枝,即如果左上角和右上角的状态都大于等于当前扩散时间,则不需要继续扩散。

最终得到的状态即为每个小时末的颜料覆盖范围。

代码

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

using namespace std;

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;

    // 初始化状态,-1 表示未覆盖
    vector<vector<int>> state(n + 1, vector<int>(m + 1, -1));

    // 使用优先队列存储需要扩散的点
    priority_queue<pair<int, pair<int, int>>, vector<pair<int, pair<int, int>>>, greater<pair<int, pair<int, int>>>> pq;

    // 起点初始时间为 0
    state[x][y] = 0;
    pq.push({0, {x, y}});

    // 分支限界法求解
    for (int i = 0; i < t; ++i) {
        // 每个小时扩散一次
        while (!pq.empty()) {
            int time = pq.top().first;
            int curX = pq.top().second.first;
            int curY = pq.top().second.second;
            pq.pop();

            // 剪枝:如果当前时间大于等于当前小时,则不需要继续扩散
            if (time >= i + 1) {
                continue;
            }

            // 向上扩散
            for (int j = curX - 1; j >= 1; --j) {
                if (state[j][curY] == -1) {
                    state[j][curY] = i + 1;
                    pq.push({i + 1, {j, curY}});
                }
            }

            // 向左上角和右上角扩散
            for (int j = 1; j <= s[i]; ++j) {
                // 左上角
                int newX = curX - j;
                int newY = curY - j;
                if (newX >= 1 && newY >= 1 && state[newX][newY] == -1) {
                    state[newX][newY] = i + 1;
                    pq.push({i + 1, {newX, newY}});
                }

                // 右上角
                newX = curX - j;
                newY = curY + j;
                if (newX >= 1 && newY <= m && state[newX][newY] == -1) {
                    state[newX][newY] = i + 1;
                    pq.push({i + 1, {newX, newY}});
                }
            }
        }
    }

    // 计算每个小时末的覆盖范围
    vector<int> ans(t, 0);
    for (int i = 0; i < t; ++i) {
        for (int j = 1; j <= n; ++j) {
            for (int k = 1; k <= m; ++k) {
                if (state[j][k] == i + 1) {
                    ans[i]++;
                }
            }
        }
    }

    // 输出结果
    for (int i = 0; i < t; ++i) {
        cout << ans[i] << ' ';
    }
    cout << endl;

    return 0;
}
Griseo 的画作:颜料扩散范围 - 分支限界法求解

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

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