【问题标题】:CPLEX OPL: Counting values between two decision variablesCPLEX OPL:计算两个决策变量之间的值
【发布时间】:2017-04-11 12:20:51
【问题描述】:

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

目前,我使用一个额外的变量来判断员工 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 变量只是为了检查一个数字是否介于两个决策变量之间,这不可能是有效的。

【问题讨论】:

    标签: cplex constraint-programming opl


    【解决方案1】:

    我会将其写成与您所做的相反 - 我将转储整数变量(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];
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-10-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多