我有一个列表Employee
和一个列表Mission
。每个任务都有开始时间和持续时间。
在 cp 模型(Google CpSat,来自 or-tools 包)中,我定义shifts = Dictionary<(int,int),IntVar>
了,shifts[(missionId, employeeId)] == 1
当且仅当该任务由该员工实现时。
我需要将每个任务分配给一个员工,显然一个员工不能同时实现两个任务。我已经写了这两个硬约束并且它们工作正常。
问题:
现在,一些任务被“联系”在一起,应该由同一名员工来实现。它们存储如下:
linkedMissions = {{1,2}, {3,4,5}}
在这里,任务一和任务二必须由同一个员工共同完成,任务三、四、五也一样。
为了编写最后一个约束,我为每个员工收集了应该链接在一起的所有班次的列表,然后我让它们都相等。
foreach (var employee in listEmployeesIds)
foreach (var missionGroup in linkedMissionsIds)
{
var linkedShifts = shifts
.Where(o => o.Key.Item2 == employee
&& missionGroup.Contains(o.Key.Item1))
.Select(o => o.Value)
.ToList();
for (var i = 0; i < linkedShifts.Count - 1; i++)
model.Add(linkedShifts[i] == linkedShifts[i + 1]);
}
然而,求解器告诉我该模型是不可行的,但是用纸和笔我可以很容易地找到一个工作计划。我有 35 名员工和 25 个任务,连接在一起的任务不重叠,所以应该没有问题。
编辑:
作为一种替代方法,正如@Laurent Perron 所建议的那样,我尝试对必须在一起的所有班次使用相同的布尔变量:
var constraintBools = new List<IntVar>();
foreach (var missionGroup in linkedMissionsIds) {
var constraintBools = new List<IntVar>();
foreach (var employee in listEmployeesIds)
{
var linkedShifts = shifts
.Where(o => o.Key.Item2 == employee
&& missionGroup.Contains(o.Key.Item1))
.Select(o => o.Value)
.ToList();
var constraint = model.NewBoolVar($"{linkedShifts.GetHashCode()}");
model.AddBoolAnd(linkedShifts).OnlyEnforceIf(constraint);
constraintBools.Add(constraint);
}
model.AddBoolOr(constraintBools);
}
但是现在,约束根本不起作用:关联的班次不是由同一名员工实现的。
我的推理有什么问题?为什么我的模型不可行?