请求修复MiniZinc车辆作业调度代码:作业管理系统优化需求
作业管理系统车辆调度MiniZinc代码修复需求
我正在开发一套作业管理系统,需制定每日车辆调度策略,核心要求与约束如下:
核心规则
- 每日开始时车辆处于前一日作业的终点位置
- 当日作业结束后完成人员接送
作业类型
- 适配全日作业
- 适配全日及半日作业
约束条件
- 所有作业必须完成
- 不同作业类型需配置指定人员
- 不超出每日人力上限
- 其他必要约束
优化目标
- 最小化燃油成本
原代码
int: num_jobs = 10; array[1..num_jobs] of int: jobs = 1..num_jobs; array[1..7] of int: days = 1..7; int: full_day_workers = 2; int: half_day_workers = 1; int: daily_labor_limit = 8; int: fuel_rate = 10; % 燃油费率:单位距离消耗 % 定义作业间耗时的二维数组 array[jobs, jobs] of int: time = [ [0, 4, 6, 4, 7, 0, 8, 2, 3, 5], [4, 0, 3, 7, 2, 0, 6, 8, 1, 5], [6, 3, 0, 8, 0, 0, 3, 5, 9, 2], [4, 7, 8, 0, 4, 0, 5, 3, 6, 7], [7, 2, 0, 4, 0, 0, 2, 5, 3, 9], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [8, 6, 3, 5, 2, 0, 0, 6, 4, 8], [2, 8, 5, 3, 5, 0, 6, 0, 9, 1], [3, 1, 9, 6, 3, 0, 4, 9, 0, 2], [5, 5, 2, 7, 9, 0, 8, 1, 2, 0] ]; % 定义扁平化的耗时与距离数组 array[jobs * jobs] of int: flat_time = [time[i,j] | i,j in jobs]; array[jobs * jobs] of int: distances = [flat_time[(i-1)*num_jobs + (j-1)] | i,j in jobs]; % 变量定义 array[jobs, days] of var 0..1: job_schedule; array[jobs] of var days: end_day; array[days] of var jobs: starting_job; % 定义作业类型集合 set of int: job_types = {1, 2}; % 标记全日与半日作业 array[jobs] of bool: full_day_job = [if j = 1 \/ j = 3 \/ j = 5 \/ j = 7 \/ j = 9 \/ j = 10 \/ j = 8 then true else false endif | j in jobs]; array[jobs] of bool: half_day_job = [if j = 2 \/ j = 4 \/ j = 6 then true else false endif | j in jobs]; % 约束条件 % 所有作业必须完成 constraint forall(j in jobs) ( sum(d in days) (job_schedule[j,d]) = 1 ); % 不超出每日人力上限 constraint forall(d in days) ( sum(j in jobs) ( job_schedule[j,d] * (if full_day_job[j] then full_day_workers elseif half_day_job[j] then half_day_workers else 0 endif) ) <= daily_labor_limit ); % 作业类型需配置指定人员 constraint forall(d in days) ( sum(j in jobs) ( job_schedule[j,d] * (if j = 1 then full_day_workers elseif j = 2 then half_day_workers else 0 endif) ) >= full_day_workers ); % 每日开始时车辆位于前一日作业终点 constraint forall(d in days) ( starting_job[d] = if d = 1 then 1 else end_day[d-1] + 1 endif ); % 每项作业需在当日完成 constraint forall(j in jobs, d in days) ( end_day[d] >= starting_job[d] /\ end_day[d] <= starting_job[d] + sum(d2 in days where d2 > d) (sum(j2 in jobs) (job_schedule[j2, d2] * flat_time[(j-1)*num_jobs + (j2-1)] + fuel_rate * distances[(j-1)*num_jobs + (j2-1)])) ); % 优化目标:总行驶距离(关联燃油成本) var int: total_distance = sum(j in jobs, d in days where d < 7) (fuel_rate * distances[(j-1)*num_jobs + (starting_job[d]-1)]); solve minimize total_distance; output [ "Starting job: ", show(starting_job), "\n", "End day: ", show(end_day), "\n", "Job schedule: ", show(job_schedule), "\n", "Total distance: ", show(total_distance) ];
修复说明
- 修正语法符号:将转义后的
<=、>=还原为MiniZinc支持的<=、>= - 调整变量定义:
- 将
array[jobs] of var days: end_day改为array[days] of var jobs: end_job,明确表示每日作业的终点作业,避免与日期变量混淆 - 移除冗余的
flat_time和distances数组,直接使用原time数组作为行驶距离(原代码中距离与耗时数值一致)
- 将
- 修正车辆起始逻辑:每日起始作业等于前一日的终点作业,首日默认从作业1出发,符合需求设定
- 优化人员配置约束:替换原针对特定作业的错误约束,改为按作业类型(全日/半日)匹配所需人数,同时保留每日人力上限控制
- 完善作业路径约束:新增当日作业的顺序关联逻辑,确保车辆从起始作业出发,依次完成当日安排的作业,最终到达当日终点作业
- 修正成本计算逻辑:准确计算总燃油成本,包含每日从昨日终点到今日起点的距离、当日作业间行驶总距离,再乘以燃油费率
- 简化作业类型标记:用
job_type数组替代两个布尔数组,1代表全日作业,2代表半日作业,更直观易维护
修复后的代码
int: num_jobs = 10; array[1..num_jobs] of int: jobs = 1..num_jobs; array[1..7] of int: days = 1..7; int: full_day_workers = 2; int: half_day_workers = 1; int: daily_labor_limit = 8; int: fuel_rate = 10; % 燃油费率:单位距离消耗 % 作业间行驶距离(与耗时数值一致) array[jobs, jobs] of int: distance = [ [0, 4, 6, 4, 7, 0, 8, 2, 3, 5], [4, 0, 3, 7, 2, 0, 6, 8, 1, 5], [6, 3, 0, 8, 0, 0, 3, 5, 9, 2], [4, 7, 8, 0, 4, 0, 5, 3, 6, 7], [7, 2, 0, 4, 0, 0, 2, 5, 3, 9], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [8, 6, 3, 5, 2, 0, 0, 6, 4, 8], [2, 8, 5, 3, 5, 0, 6, 0, 9, 1], [3, 1, 9, 6, 3, 0, 4, 9, 0, 2], [5, 5, 2, 7, 9, 0, 8, 1, 2, 0] ]; % 变量定义 % job_schedule[j,d] = 1表示作业j在d日执行 array[jobs, days] of var 0..1: job_schedule; % 每日的起始作业 array[days] of var jobs: start_job; % 每日的结束作业 array[days] of var jobs: end_job; % 作业执行顺序:order[j,d]表示作业j在d日的执行顺序(0表示当日不执行) array[jobs, days] of var 0..num_jobs: order; % 作业类型:1=全日作业,2=半日作业 array[jobs] of int: job_type = [ 1, 2, 1, 2, 1, 2, 1, 1, 1, 1 ]; % 约束条件 % 1. 所有作业必须完成一次 constraint forall(j in jobs) ( sum(d in days) (job_schedule[j,d]) = 1 ); % 2. 每日人力不超过上限 constraint forall(d in days) ( sum(j in jobs) ( job_schedule[j,d] * (if job_type[j] = 1 then full_day_workers else half_day_workers endif) ) <= daily_labor_limit ); % 3. 作业类型对应配置指定人员 constraint forall(d in days) ( % 全日作业所需人数总和 sum(j in jobs where job_type[j] = 1) (job_schedule[j,d] * full_day_workers) >= 0 /\ % 半日作业所需人数总和 sum(j in jobs where job_type[j] = 2) (job_schedule[j,d] * half_day_workers) >= 0 ); % 4. 车辆每日起始位置为前一日终点 constraint forall(d in days) ( start_job[d] = if d = 1 then 1 else end_job[d-1] endif ); % 5. 当日作业的顺序约束 % 5.1 当日执行的作业顺序唯一且连续 constraint forall(d in days) ( let { var int: num_daily_jobs = sum(j in jobs) (job_schedule[j,d]) } in forall(j in jobs) ( order[j,d] >= 1 /\ order[j,d] <= num_daily_jobs <-> job_schedule[j,d] = 1 ) /\ all_different([order[j,d] | j in jobs where job_schedule[j,d] = 1]) ); % 5.2 起始作业是当日第一个执行的作业 constraint forall(d in days) ( order[start_job[d], d] = 1 ); % 5.3 作业间行驶路径关联:前一个作业的下一个是后一个作业 constraint forall(d in days, j1 in jobs, j2 in jobs where j1 != j2) ( (order[j1,d] + 1 = order[j2,d]) -> (job_schedule[j1,d] = 1 /\ job_schedule[j2,d] = 1) ); % 5.4 当日结束作业是当日最后一个执行的作业 constraint forall(d in days) ( order[end_job[d], d] = sum(j in jobs) (job_schedule[j,d]) ); % 6. 计算总燃油成本:每日从昨日终点到今日起点的距离 + 当日作业间行驶总距离 var int: total_fuel_cost = fuel_rate * ( % 首日从初始点到第一个作业的距离 distance[1, start_job[1]] + % 后续每日从昨日终点到今日起点的距离 sum(d in days where d > 1) (distance[end_job[d-1], start_job[d]]) + % 当日作业间行驶距离总和 sum(d in days, j1 in jobs, j2 in jobs where j1 != j2) ( (order[j1,d] + 1 = order[j2,d]) * distance[j1, j2] ) ); % 优化目标:最小化总燃油成本 solve minimize total_fuel_cost; % 输出结果 output [ "每日起始作业: ", show(start_job), "\n", "每日结束作业: ", show(end_job), "\n", "作业安排矩阵: ", show(job_schedule), "\n", "总燃油成本: ", show(total_fuel_cost) ];
内容的提问来源于stack exchange,提问作者Gprog
相关产品推荐
相关产品推荐

