返回题解分享
讨论 / 题解分享/ 帖子详情

魔法炼金术——三步炼成大挑战! - 题解

魔法炼金术——三步炼成大挑战!



#### tag

模拟

#### 题意简述

一个原材料需要经过三个步骤才能获得成品,为了方便我们这里把处理0次,1次,2次的数量记为 $f_1, f_2, f_3$,现在步骤一有 $n_1$ 台机器(即在同一时间最多同时处理 $n_1$ 个 $f_1$),每台步骤一的机器处理当前步骤需要 $t_1$ 个单位的时间。步骤二三同理,问要得到 $k$ 个成品,最少需要多少时间。

#### 题解思路

我们可以考虑直接模拟,我们可以把每一个步骤的过程抽象成一个任务三元组 $(x,y,z)$,其中 $x$ 表示完成的时间点,$y$ 表示步骤的编号,$z$ 表示当前任务占用了多少台对应步骤的机器。我们用一个优先队列来维护当前的任务。对于一个任务,完成之后,我们可以得到 $z$ 个步骤 $y + 1$ 的产物,同时空出 $z$ 台可以用来生产 $y$ 的机器。此时我们可以检查步骤 $y + 1$ 的机器和 $y$ 的原料 $f_y$ 是否还有空余,如果有空余,我们可以继续加入新的任务。重复上述过程直到优先队列为空即可。最后的时间点就是答案。

部分细节在代码注释中体现。

#### 参考代码

void solve()
{
    // n:每个步骤的机器的数量,t:每个步骤消耗的时间,f:每个步骤的原料数量,v:每个步骤空闲机器的数量
    array<int, 5> n, t, f, v;
    cin >> f[1];
    cin >> n[1] >> n[2] >> n[3];
    cin >> t[1] >> t[2] >> t[3];
    // 初始化
    int ans = 0;
    f[2] = 0, f[3] = 0;
    v[1] = n[1], v[2] = n[2], v[3] = n[3];
    // 任务三元组,first:完成的时间点,second:步骤的编号,third:当前任务占用了多少台对应步骤的机器
    priority_queue<piii, vector<piii>, greater<piii>> heap;
    // 最开始,处理步骤一,他会在t[1]时间后完成,占用n[1]台机器,使用min(n[1], f[1])个原料
    heap.push({ans + t[1], 1, min(n[1], f[1])});
    // 更新步骤一原料和空闲机器数量
    f[1] -= min(v[1], f[1]);
    v[1] -= min(v[1], f[1]);
    while(heap.size())
    {
        // 当前时间点,处理完成的步骤编号,当前步骤多出的空闲机器数量
        auto [now, id, cnt] = heap.top();
        // 更新答案
        ans = now;
        heap.pop();
        // 当前步骤完成后,会生成cnt个步骤id+1的原料,同时空出cnt台可以用来生产id的机器
        f[id + 1] += cnt;
        v[id] += cnt;
        // 检查步骤id+1的机器和id的原料f[id]是否还有空余,如果有空余,我们可以继续加入新的任务
        for(int i = 1; i <= 3; i ++)
            if(f[i] and v[i])
            {
                heap.push({now + t[i], i, min(f[i], v[i])});
                int tmp = min(f[i], v[i]);
                f[i] -= tmp;
                v[i] -= tmp;
            }
    }
    cout << ans << '\n';
}
0 回复 0 转发 2 喜欢 5 阅读
回复 (0)
默认 最新
暂无回复,快来抢沙发!