按给定顺序逐个安排操作,在工件前序完成后寻找目标机器最早连续空闲时间段。
OJ: luogu
题目 ID: P1065
难度:普及/提高-
标签:模拟调度python
日期: 2026-06-19 02:34
题意
有 m 台机器和 n 个工件。每个工件有 m 道工序,每道工序指定机器和加工时间。题目给出安排顺序,要求每次把当前工序尽量早地插入目标机器的空闲时间段,同时满足同一工件前序工序已完成。
思路
用三个数组维护状态:
next_operation[job]:某个工件下一道要安排的工序编号;job_finish_time[job]:某个工件上一道工序完成时间;busy[machine][time]:某台机器某个时刻是否被占用。
处理安排顺序中的一个工件 job 时:
- 找到它当前工序的目标机器和加工时长;
- 开始时间不能早于
job_finish_time[job]; - 从这个时间开始向后找,直到找到一段长度为
duration的连续空闲时间; - 标记这段机器时间为占用;
- 更新工件完成时间和答案。
这正好模拟了题目要求的“尽量靠前插入”。
Python 知识
/home/rainboy/mycode/hugo-blog/content/program_language/python/oj_input_output_cheatsheet.md:多行整数矩阵可以逐行input().split()。/home/rainboy/mycode/hugo-blog/content/program_language/python/brute_force_validation.md:二维列表要逐行创建,避免浅拷贝。- 布尔矩阵
busy[machine][time]适合表示时间轴占用。 - 遇到冲突时把
start推到冲突时间之后,可以减少无效检查。
代码
cpp
#include <bits/stdc++.h>
using namespace std;
const int MAXM = 25; // 最大机器数
const int MAXN = 25; // 最大工件数
const int MAXT = 10005; // 时间轴上限
int m, n;
int order_list[MAXM * MAXN]; // 安排顺序:按顺序列出每次要安排的工件编号
int machine_id[MAXN][MAXM]; // machine_id[job][step] 工件 job 的第 step 道工序在哪台机器
int cost_time[MAXN][MAXM]; // cost_time[job][step] 工件 job 的第 step 道工序加工时长
int next_step[MAXN]; // 工件 job 下一次要安排第几道工序
int finish_time[MAXN]; // 工件 job 已安排完的最后时间(最早可开始下一道工序的时间)
bool busy[MAXM][MAXT]; // busy[machine][time] 标记该机器该时刻是否被占用
/* ===== 输入层:读取全部原始数据 ===== */
void read_input() {
cin >> m >> n;
int tot = m * n;
for (int i = 1; i <= tot; i++)
cin >> order_list[i];
for (int job = 1; job <= n; job++)
for (int step = 1; step <= m; step++)
cin >> machine_id[job][step];
for (int job = 1; job <= n; job++)
for (int step = 1; step <= m; step++)
cin >> cost_time[job][step];
}
/* ===== 调度层:核心调度逻辑 ===== */
// 在机器 mac 上从 start 时刻向后找一段长度为 len 的连续空闲时间。
int find_available_slot(int mac, int start, int len) {
while (true) {
bool ok = true;
for (int t = start; t < start + len; t++) {
if (busy[mac][t]) {
start = t + 1; // 遇到冲突,跳到冲突时刻之后继续找
ok = false;
break;
}
}
if (ok) break;
}
return start;
}
int schedule_all() {
int tot = m * n;
int answer = 0;
for (int i = 1; i <= tot; i++) {
int job = order_list[i]; // 当前要安排的工件
int step = ++next_step[job]; // 当前安排的是该工件的第几道工序
int mac = machine_id[job][step]; // 目标机器
int len = cost_time[job][step]; // 加工时长
// 开始时间不能早于该工件上一道工序完成的时间
int start = finish_time[job];
// 在目标机器上找到最早的一段连续空闲时间段
start = find_available_slot(mac, start, len);
// 占用该机器上的 [start, start+len) 时间段
for (int t = start; t < start + len; t++)
busy[mac][t] = true;
finish_time[job] = start + len;
if (answer < finish_time[job])
answer = finish_time[job];
}
return answer;
}
/* ===== 主控层:组装各层 ===== */
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
read_input();
int ans = schedule_all();
cout << ans << '\n';
return 0;
}python
machine_count, job_count = map(int, input().split())
order = [x - 1 for x in map(int, input().split())]
machine_for = [list(map(lambda x: int(x) - 1, input().split())) for _ in range(job_count)]
duration_for = [list(map(int, input().split())) for _ in range(job_count)]
max_time = job_count * machine_count * 20 + 1
busy = [[False for _ in range(max_time)] for _ in range(machine_count)]
next_operation = [0 for _ in range(job_count)]
job_finish_time = [0 for _ in range(job_count)]
answer = 0
for job in order:
operation = next_operation[job]
machine = machine_for[job][operation]
duration = duration_for[job][operation]
start = job_finish_time[job]
while True:
can_place = True
for time in range(start, start + duration):
if busy[machine][time]:
start = time + 1
can_place = False
break
if can_place:
break
for time in range(start, start + duration):
busy[machine][time] = True
finish = start + duration
job_finish_time[job] = finish
next_operation[job] += 1
answer = max(answer, finish)
print(answer)复杂度
设最终时间轴长度为 T,共有 n*m 个操作。直接时间轴模拟复杂度约为
总结
调度题不要急着找复杂算法。题目已经规定唯一的靠前插入规则,按顺序找目标机器最早可行空档即可。