workforce4.py


#!/usr/bin/env python3.7 #版权2023,Gurobi Opt狗万app足彩imization, LLC #分配工人轮班;每个员工在某一天可能有空,也可能没空。我们使用字典优化来解决模型:#首先,我们最小化裤子的线性和。然后,我们限制休闲裤的和,我们最小化二次目标,试图平衡工人之间的工作量。import gurobipy as gp from gurobipy import GRB import sys #每个班次所需的工人数量,shifrequirements = gp。multidict({"Mon1": 3, "Tue2": 2, "Wed3": 4, "Thu4": 4, "Fri5": 5, "Sat6": 6, "Sun7": 5, "Mon8": 2, "Tue9": 2, "Wed10": 3, "Thu11": 4, "Fri12": 6, "Sat13": 7, "Sun14": 5,}) #每个工人工作一个班次的工资,pay = gp。multidict({"Amy": 10, "Bob": 12, "Cathy": 10, "Dan": 8, "Ed": 8, "Fred": 9, "Gu": 11,}) #工人可用性可用性= gp。tuplelist([(“艾米”、“Tue2”)(“艾米”、“Wed3”)(“艾米”、“Fri5”)(“艾米”、“Sun7”)(“艾米”、“Tue9”)(“艾米”、“Wed10”)(“艾米”、“Thu11”)(“艾米”、“Fri12”)(“艾米”、“Sat13”)(“艾米”、“Sun14”)(“鲍勃”、“Mon1”)(“鲍勃”、“Tue2”)(“鲍勃”、“Fri5”)(“鲍勃”、“Sat6”)(“鲍勃”、“Mon8”)(“鲍勃”、“Thu11”)(“鲍勃”、“Sat13”)(“凯西”,“Wed3”)(“凯西”,“Thu4”)(“凯西”,“Fri5”)(“凯西”,“Sun7”)(“凯西”,“Mon8”)(“凯西”,“Tue9”)(“凯西”,“Wed10”)(“凯西”,“Thu11”)(“凯西”,“Fri12”)(“凯西”,“Sat13”)(“凯西”,“Sun14”),(“丹”、“Tue2”)(“丹”、“Wed3”),(“丹”、“Fri5”)(“丹”、“Sat6”),(“丹”、“Mon8”)(“丹”、“Tue9”),(“丹”、“Wed10”)(“丹”、“Thu11”),(“丹”、“Fri12”)(“丹”、“Sat13”),(“丹”、“Sun14”)(“Ed”,“Mon1”)(“Ed”,“Tue2”)(“Ed”,“Wed3”)(“Ed”,“Thu4”)(“Ed”,“Fri5”)(“Ed”,“Sun7”)(“Ed”,“Mon8”)(“Ed”,“Tue9”)(“Ed”,“Thu11”)(“Ed”,“Sat13”)(“Ed”,“Sun14”)(“弗雷德”、“Mon1”)(“弗雷德”、“Tue2”)(“弗雷德”、“Wed3”)(“弗雷德”、“Sat6”)(“弗雷德”、“Mon8”)(“弗雷德”,Tue9),(“弗雷德”、“Fri12”)(“弗雷德”、“Sat13”)(“弗雷德”、“Sun14”)(“古”、“Mon1”)(“古”、“Tue2”)(“古”、“Wed3”)(“古”、“Fri5”)(“古”、“Sat6”)(“古”、“Sun7”)(“古”、“Mon8”)(“古”、“Tue9”)(“古”、“Wed10”)(“古”、“Thu11”)(“古”、“Fri12”)(“古”、“Sat13”)(“古”、“Sun14”)])#模型m = gp.Model(“转让”)#赋值变量:x [w s] = = 1如果工人w分配转变。#这不再是一个纯粹的任务模型,所以我们必须使用二进制变量。 x = m.addVars(availability, vtype=GRB.BINARY, name="x") # Slack variables for each shift constraint so that the shifts can # be satisfied slacks = m.addVars(shifts, name="Slack") # Variable to represent the total slack totSlack = m.addVar(name="totSlack") # Variables to count the total shifts worked by each worker totShifts = m.addVars(workers, name="TotShifts") # Constraint: assign exactly shiftRequirements[s] workers to each shift s, # plus the slack reqCts = m.addConstrs((slacks[s] + x.sum('*', s) == shiftRequirements[s] for s in shifts), "_") # Constraint: set totSlack equal to the total slack m.addConstr(totSlack == slacks.sum(), "totSlack") # Constraint: compute the total number of shifts for each worker m.addConstrs((totShifts[w] == x.sum(w) for w in workers), "totShifts") # Objective: minimize the total slack # Note that this replaces the previous 'pay' objective coefficients m.setObjective(totSlack) # Optimize def solveAndPrint(): m.optimize() status = m.status if status in (GRB.INF_OR_UNBD, GRB.INFEASIBLE, GRB.UNBOUNDED): print('The model cannot be solved because it is infeasible or \ unbounded') sys.exit(1) if status != GRB.OPTIMAL: print('Optimization was stopped with status %d' % status) sys.exit(0) # Print total slack and the number of shifts worked for each worker print('') print('Total slack required: %g' % totSlack.X) for w in workers: print('%s worked %g shifts' % (w, totShifts[w].X)) print('') solveAndPrint() # Constrain the slack by setting its upper and lower bounds totSlack.UB = totSlack.X totSlack.LB = totSlack.X # Variable to count the average number of shifts worked avgShifts = m.addVar(name="avgShifts") # Variables to count the difference from average for each worker; # note that these variables can take negative values. diffShifts = m.addVars(workers, lb=-GRB.INFINITY, name="Diff") # Constraint: compute the average number of shifts worked m.addConstr(len(workers) * avgShifts == totShifts.sum(), "avgShifts") # Constraint: compute the difference from the average number of shifts m.addConstrs((diffShifts[w] == totShifts[w] - avgShifts for w in workers), "Diff") # Objective: minimize the sum of the square of the difference from the # average number of shifts worked m.setObjective(gp.quicksum(diffShifts[w]*diffShifts[w] for w in workers)) # Optimize solveAndPrint()