CPLEX OPL:计算两个决策变量之间的值

时间:2017-04-11 12:20:51

标签: cplex constraint-programming opl

情况如下:我正在为工作场所制定每日时间表。每天分为时段,每个时段我都知道必须有多少员工。该计划是使用两个整数决策变量创建的,这些变量描述了每个员工的到达和离开时间段。

目前,我使用一个额外的变量来判断员工 i 是否在 t 时工作,然后我在每个时间段对员工进行总结以与需求。我的代码可归结为以下内容:

using CP;

tuple TimeSlot {
    key int id;
    int minEmploy;
}
{TimeSlot} TSlots = ...;
{int} timeSlots = {t.id|t in TSlots};
int tMax = max(t in timeSlots) t;
range dayRange = 0..tMax;

range allEmployees = 1..10;

dvar int dayStart[allEmployees] in dayRange;
dvar int dayEnd[allEmployees] in dayRange;
dvar int workTimeT[allEmployees][timeSlots] in 0..1;

minimize ...;

subject to {
    /*Indicator constraints*/
    forall(i in allEmployees){
        forall(t in timeSlots:t>0){
            dayStart[i] <= t && t <= dayEnd[i] => workTimeT[i][t] == 1;
            dayEnd[i] < t || t < dayStart[i] => workTimeT[i][t] == 0;
        }
    } 
    /*Must satisfy requirement*/
    forall(t in timeSlots:t>0){
        sum(i in allEmployees) workTimeT[i][t] >= item(TSlots,<t>).minEmploy;
    }
}

有没有办法绕过这个额外的变量?添加 #employees #timeslots 变量可能是有效的,只是为了检查一个数字是否在两个决策变量之间。

1 个答案:

答案 0 :(得分:0)

我会把它写成你所做的反转 - 我会转储整数变量(dayStart [i]和dayEnd [i])并用布尔值替换它们(dayStart [i] [t]和dayStart [i] [T])。 CPLEX和其他解算器非常善于使用这些布尔值,尽管存在更多变量,它实际上可能比你尝试的更快地解决。

它还可以更容易地找出有多少人正在工作 - 它已经开始工作的人数减去完成工作的人数(假设没有围绕墓地转移,你在哪里开始工作一天,第二天早上结束,你的配方似乎认为永远不会发生这种情况。)

dvar int dayStart[allEmployees][timeSlots] in 0..1;
dvar int dayEnd[allEmployees][timeSlots] in 0..1;

forall(i in allEmployees) {
    /* Every employee starts exactly once */
    sum(t in timeSlots) dayStart[i][t] == 1;

    /* Every employee stops exactly once */
    sum(t in timeSlots) dayEnd[i][t] == 1;

   /* You must start before you stop */
   forall(t in timeSlots) dayEnd[i][t] <= sum(tstart in timeSlots: tstart < t) dayStart[i][tstart];
}

/* the number of employees working is the number who have started minus
   the number who have stopped */
dexpr int NumWorking[t in timeSlots] = 
    sum(tstart in timeSlots: tstart <= t) dayStart[i][tstart] 
    -
    sum(tend in timeSlots: tend < t) dayEnd[i][tend];

/* Make sure we've got enough people working */
forall(t in timeSlots)
    NumWorking[t] >= item(TSlots,<t>).minEmploy;

如果你真的想要整数的开始和结束时间,你可以用布尔值来轻松写出来:

dvar int+ employeeStartTime[allEmployees];
dvar int+ employeeEndTime[allEmployees];

forall(i in allEmployees) {
    employeeStartTime == sum(t in timeSlots) t*dayStart[i][t];
    employeeEndTime == sum(t in timeSlots) t*dayEnd[i][t];
}