У меня есть список Employee
и список Mission
.
У каждой миссии есть время начала и продолжительность.
В модели cp (Google CpSat, из пакета or-tools) я определил shifts = Dictionary<(int,int),IntVar>
, где shifts[(missionId, employeeId)] == 1
, если и только если эта миссия выполняется этим сотрудником.
Мне нужно назначить каждую миссию ровно одному сотруднику, и, очевидно, один сотрудник не может выполнять две миссии одновременно. Я уже написал эти два жестких ограничения, и они работают нормально.
Проблема:
Теперь некоторые миссии «связаны» вместе и должны выполняться одним и тем же сотрудником. Они хранятся следующим образом:
linkedMissions = {{1,2}, {3,4,5}}
Здесь миссии 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 миссий, миссии, которые связаны друг с другом, не пересекаются, поэтому проблем быть не должно.
EDIT:
В качестве альтернативного подхода, предложенного @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);
}
Но теперь ограничение просто не работает: связанные изменения не осуществляются одним и тем же сотрудником.
Что не так в моих рассуждениях? Почему моя модель неосуществима?