1 条题解
-
2
魔法炼金术——三步炼成大挑战!
tag
模拟
题意简述
一个原材料需要经过三个步骤才能获得成品,为了方便我们这里把处理0次,1次,2次的数量记为 ,现在步骤一有 台机器(即在同一时间最多同时处理 个 ),每台步骤一的机器处理当前步骤需要 个单位的时间。步骤二三同理,问要得到 个成品,最少需要多少时间。
题解思路
我们可以考虑直接模拟,我们可以把每一个步骤的过程抽象成一个任务三元组 ,其中 表示完成的时间点, 表示步骤的编号, 表示当前任务占用了多少台对应步骤的机器。我们用一个优先队列来维护当前的任务。对于一个任务,完成之后,我们可以得到 个步骤 的产物,同时空出 台可以用来生产 的机器。此时我们可以检查步骤 的机器和 的原料 是否还有空余,如果有空余,我们可以继续加入新的任务。重复上述过程直到优先队列为空即可。最后的时间点就是答案。
部分细节在代码注释中体现。
参考代码
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'; }
- 1
信息
- ID
- 220
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 6
- 已通过
- 3
- 上传者