使用标准/简单护理实例:排程
我正试图强制要求某一组/团队的护士连续分配几天。如下所示,护士1-9分成“小组”。如果首先分配护士9,那么组(4和7)的其他成员应该分配到接下来的几天。
我认为,我可以通过计算一组成员一天又一天分配的次数来实现这一点,但我无法计算何时发生这种情况,即day_i和day_i+1都分配给来自同一组的护士。
groups = [[3,7,8],[1,6],[5],[4,9,7]] #nurses 3,7,8 are in same group
...
for g in groups:
for d1, d2 in zip(all_days[:-1],all_days[1:]):
d1_alloc = sum(shifts[(n, d1, s)] for n in g)
d2_alloc = sum(shifts[(n, d2, s)] for n in g)
# ??? how to say only count when both sums = 1/true ???
# for a group of 3, i.e. [3,7,8] this should occur twice within period完整法典:
from ortools.sat.python import cp_model
all_days = range(1,10)
all_nurses = range(1,10)
groups = [[3,7,8],[1,6],[5],[4,9,7]] #nurses 3,7,8 are in same group
s=1 #1 shift only
model = cp_model.CpModel()
shifts = {}
for d in all_days:
for n in all_nurses:
shifts[(n, d, s)] = model.NewBoolVar('shift_n%sd%is%i' % (n, d, s))
# one nurse per shift
for d in all_days:
model.Add(sum(shifts[(n, d, s)] for n in all_nurses) == 1)
# everyone works a shift
for n in all_nurses:
model.Add(sum(shifts[(n, d, s)] for d in all_days) == 1)
# nurses within group should be allocated days one after another
# order of groups is not important - last group [4,9,7] could be allocated firts
# order within groups is not important - can be 7,4,9
for g in groups:
for d1, d2 in zip(all_days[:-1],all_days[1:]):
d1_alloc = sum(shifts[(n, d1, s)] for n in g)
d2_alloc = sum(shifts[(n, d2, s)] for n in g)
# ??? how to say only count when both sums 1/true ???
# for a group of 3, i.e. [3,7,8] this should occur twice within period
solver = cp_model.CpSolver()
solver.Solve(model)
for d in all_days:
for n in all_nurses:
if solver.Value(shifts[(n, d, s)]) == 1:
print('Day: '+str(d)+' = Nurse '+str(n))编辑:可以使用以下逻辑来实现这一点
for group in groups:
for n1, n2 in zip(group[:-1],group[1:]):
for d in all_days[:-1]:
model.AddBoolOr([shifts[n1, d, 1],shifts[n2, d+1, 1].Not()])
model.AddBoolOr([shifts[n1, d, 1].Not(),shifts[n2, d+1, 1]])此解决方案是限制性的-分配必须遵循与所列组相同的顺序。第3,7,8组总是3,7,8,但不是7,3,8或8,3,7,例如.这也很好。
还必须确保第一天从一开始就分配给某个人。Model.Add(3,1,5,4中n的移位(n,1,s) ==1)
如果只有最多2名成员的组,以下将允许任何一种命令。比如第三组,第七组.3、7或7.3。
for group in groups:
for n1, n2 in zip(group[:-1],group[1:]):
#Day1
model.AddImplication(shifts[n1, 1, 1],shifts[n2, 2, 1])
model.AddImplication(shifts[n2, 1, 1],shifts[n1, 2, 1])
#Day2 + must check preceding day to avoid circular/repeated allocations
for d in all_days[1:-1]:
model.AddImplication(shifts[n1, d, 1],shifts[n2, d+1, 1]).OnlyEnforceIf(shifts[n2, d-1, 1].Not())
model.AddImplication(shifts[n2, d, 1],shifts[n1, d+1, 1]).OnlyEnforceIf(shifts[n1, d-1, 1].Not())编辑2:以下内容可用于任何大小的组.
for g in groups:
for i in range(0,len(g)):
#1 cycle for every group order [3,7,2], [7,2,3],[2,3,7]
for d in all_days[:-(len(g)-1)]:
conditions_met = [shifts[g[0], d, 1]] #n1 allocated today
if d > 1:
#ensure group members not allocated previous day
for n in g:
conditions_met.append(shifts[n, d-1, 1].Not())
#apply rules for next x days - depending on size of group
for day in range(d+1,d+len(g)):
or_cond = []
for n in g[1:]:
or_cond.append(shifts[n,day,1])
model.AddBoolOr(or_cond).OnlyEnforceIf(conditions_met)
x = g.pop(0)
g.append(x)发布于 2020-06-04 09:52:19
对于更复杂的约束,我建议查看此移位调度示例
特别是包含min和max序列约束。
https://stackoverflow.com/questions/62189770
复制相似问题