// 选择和定义一个model,然后设置所需的前置数据和限制条件 model = cp_model.CpModel() model.NewBoolVar(...) model.AddExactlyOne(...) model.Add(...)// 选择和定义一个solver,然后针对model进行optimizate solver = cp_model.CpSolver() status = solver.Solve(model, solution_printer)// 创建一个矩阵进行拟合 work ={} for e inrange(num_employees):for s inrange(num_shifts):for d inrange(num_days):work[e, s, d]= model.NewBoolVar('work%i_%i_%i'%(e, s, d)) // 下面是打印结果的算法 if status == cp_model.OPTIMAL or status == cp_model.FEASIBLE:print()header =' 'for w inrange(num_weeks):header +='M T W T F S S 'print(header)for e inrange(num_employees):schedule =''for d inrange(num_days):for s inrange(num_shifts):if solver.BooleanValue(work[e, s, d]):// NOTE: 获取优化算法出来的结果schedule += shifts[s]+' 'print('worker %i: %s'%(e, schedule))print()
num_employees =4// 员工数,改为目标的员工数 num_weeks =5// 工作天数,目标是排一个月的班表,改为5周 shifts =['O','M','A','N']// 班期,和目标一样# Fixed assignment: (employee, shift, day). # 固定前两天的,排班前得动态调整下 fixed_assignments =[(0,0,0),(1,1,0),(2,2,0),(3,3,0),(0,0,1),(1,1,1),(2,2,1),(3,3,1), ]# Request: (employee, shift, day, weight) # 员工想要固定休息的时间(位置),权重值我理解为代表拟合时可调整的优先级 requests =[# Employee 3 does not want to work on the first Saturday (negative weight for the Off shift).(3,0,5,-2),# Employee 2 does not want a night shift on the first Friday (positive weight).(2,3,4,4) ]# Shift constraints on continuous sequence : # (shift, hard_min, soft_min, min_penalty, # soft_max, hard_max, max_penalty) # hard_min: 硬性限制,在周期内最少连续要上的班期天数 # soft_min: 软性限制,在周期内最少连续要上的班期天数 # soft_max和hard_max同上去理解 shift_constraints =[# One or two consecutive days of rest, this is a hard constraint.(0,1,1,0,2,2,0),# betweem 2 and 3 consecutive days of night shifts, 1 and 4 are# possible but penalized.(3,1,2,20,3,4,5), ]# Weekly sum constraints on shifts days: # (shift, hard_min, soft_min, min_penalty, # soft_max, hard_max, max_penalty) weekly_sum_constraints =[# 每周最少要休息的天数(0,1,2,7,2,3,4), ]# Penalized transitions: # (previous_shift, next_shift, penalty (0 means forbidden)) penalized_transitions =[# 尽量避免午班换晚班(2,3,4),# 晚班不能接着早班(3,1,0), ]# daily demands for work shifts (morning, afternon, night) for each day # of the week starting on Monday. # 每个班期最少要有多少人,我这里的现实问题是有一个人就行了 weekly_cover_demands =[(1,1,1),# Monday(1,1,1),# Tuesday(1,1,1),# Wednesday(1,1,1),# Thursday(1,1,1),# Friday(1,1,1),# Saturday(1,1,1),# Sunday ]# Penalty for exceeding the cover constraint per shift type. excess_cover_penalties =(2,2,5)num_days = num_weeks *7 num_shifts =len(shifts)
画甘特图
技术栈中,选择了matplot去画甘特图,也是现学现卖。
# Generate plot image. [reference: https://www.geeksforgeeks.org/python-basic-gantt-chart-using-matplotlib]shifts_colors =['white','tab:green','tab:orange','tab:blue']if status == cp_model.OPTIMAL or status == cp_model.FEASIBLE:offset =2# Declaring a figure "gnt"fig, gnt = plt.subplots()# Setting Y-axis limitsgnt.set_ylim(0, num_employees *15)# Setting X-axis limitsgnt.set_xlim(1, num_days + offset)# Setting labels for x-axis and y-axisgnt.set_xlabel('Dates')gnt.set_ylabel('Employees')# Setting ticks on y-axis# gnt.set_yticks([15, 25, 35, 45])gnt.set_xticks(list(range(1, num_days + offset,1)))gnt.set_yticks(list(range(15,(num_employees +1)*10+5,10)))# Labelling tickes of y-axisgnt.set_yticklabels(employees_names)# Setting graph attributegnt.grid(True)for e inrange(num_employees):for d inrange(num_days):for s inrange(num_shifts):if solver.BooleanValue(work[e, s, d]):gnt.broken_barh([(d+1, d+2)],(10*(e+1),9),facecolors=(shifts_colors[s]))plt.savefig("gantt1.png")