如何解决限制平衡每日覆盖
这是我的问题表述的简化版本:
from ortools.sat.python import cp_model
def solve_shift_scheduling():
num_employees = 6
num_weeks = 4
shifts = ['.','M']
fixed_assignments = [
(0,1,0),(0,2),5),(1,1),6),(2,(5,5)]
requests = [
(3,3,-2),(3,4,(4,2,-2)]
weekly_cover_demands = [
(4,),# Monday
(4,# Tuesday
(4,# Wednesday
(4,# Thursday
(4,# Friday
(4,# Saturday
(4,# Sunday
]
employee_max_shifts = [
(1,3),# employee 0
(1,# employee 1
(1,4),# employee 2
(1,# employee 3
(1,# employee 4
(1,# employee 5
]
num_days = num_weeks * 7
num_shifts = len(shifts)
model = cp_model.CpModel()
work = {}
for e in range(num_employees):
for s in range(num_shifts):
for d in range(num_days):
work[e,s,d] = model.NewBoolVar('work%i_%i_%i' % (e,d))
# Linear terms of the objective in a minimization context.
obj_int_vars = []
obj_int_coeffs = []
obj_bool_vars = []
obj_bool_coeffs = []
# Exactly one shift per day.
for e in range(num_employees):
for d in range(num_days):
model.Add(sum(work[e,d] for s in range(num_shifts)) == 1)
# Fixed assignments.
for e,d in fixed_assignments:
model.Add(work[e,d] == 1)
# Employee requests
for e,d,w in requests:
obj_bool_vars.append(work[e,d])
obj_bool_coeffs.append(w)
# Employee shifts constraint
for e in range(num_employees):
for w in range(num_weeks):
s,max_shifts = employee_max_shifts[e]
works = [work[e,d + w * 7] for d in range(7)]
total_shifts = model.NewIntvar(0,max_shifts,'')
model.Add(total_shifts==sum(works))
# Cover constraints
for s in range(1,num_shifts):
for w in range(num_weeks):
for d in range(7):
works = [work[e,w * 7 + d] for e in range(num_employees)]
demand = weekly_cover_demands[d][s - 1]
worked = model.NewIntvar(0,demand,'')
model.Add(worked == sum(works))
name = 'under_demand: (shift={},week={},day={})'.format(s,w,d)
under = model.NewIntvar(0,name)
model.Add(under == demand - worked)
obj_int_vars.append(under)
obj_int_coeffs.append(20)
# Objective
model.Minimize(
sum(obj_bool_vars[i] * obj_bool_coeffs[i]
for i in range(len(obj_bool_vars))) +
sum(obj_int_vars[i] * obj_int_coeffs[i]
for i in range(len(obj_int_vars))))
# Solve the model.
solver = cp_model.cpsolver()
solver.parameters.num_search_workers = 8
solver.parameters.max_time_in_seconds = 600
solution_printer = cp_model.ObjectiveSolutionPrinter()
status = solver.solveWithSolutionCallback(model,solution_printer)
# Print solution.
if status == cp_model.OPTIMAL or status == cp_model.FEASIBLE:
print()
header = ' '
for w in range(num_weeks):
header += 'M T W T F S S '
print(header)
for e in range(num_employees):
schedule = ''
for d in range(num_days):
for s in range(num_shifts):
if solver.BooleanValue(work[e,d]):
schedule += shifts[s] + ' '
print('worker %i: %s' % (e,schedule))
# Balance Coverage
for s in range(1,num_shifts):
for w in range(num_weeks):
each_days_gap = []
daily_demands = []
for d in range(7):
demand = weekly_cover_demands[d][s - 1]
daily_demands.append(demand)
works = [work[e,w*7+d] for e in range(num_employees)]
demand_gap = model.NewIntvar(0,'')
model.Add((demand - sum(works)) == demand_gap)
each_days_gap.append(demand_gap)
min_demand_gap = model.NewIntvar(0,max(daily_demands),'')
max_demand_gap = model.NewIntvar(0,'')
model.Addminequality(min_demand_gap,each_days_gap)
model.AddMaxEquality(max_demand_gap,each_days_gap)
name = 'target_gap: (shift={},week={})'.format(s,w)
delta = model.NewIntvar(0,name)
model.Add(delta == max_demand_gap-min_demand_gap)
obj_int_vars.append(delta)
obj_int_coeffs.append(10)
通过添加此规则,它会导致运行时间增加 20 倍,这意味着随着附加约束的添加,问题开始需要 10 多分钟才能解决。有没有更有效的方法来实现上述规则?
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。