【问题标题】:consecutive days constraint in linear programming线性规划中的连续天数约束
【发布时间】:2022-01-04 15:04:02
【问题描述】:

对于轮班优化问题,我在 PuLP 中定义了一个二进制变量,如下所示:

pulp.LpVariable.dicts('VAR', (range(D), range(N), range(T)), 0, 1, 'Binary')

在哪里

  1. D = 我们创建的每个计划中的 # 天(=28 或 4 周)
  2. N = 工人数
  3. T = 轮班类型 (=6)

对于第 5 和第 6 类工作班次(索引为 4 和 5),我需要添加一个约束条件,即任何从事这些班次工作的工人必须连续工作 7 天......而不是任何 7 天,而是从星期一开始的 7 天(又名一整周)。我尝试按如下方式定义约束,但是当我添加此约束并尝试解决问题时,我得到了一个不可行的解决方案(之前没有它也可以工作)

我知道这个约束(以及之前的其他约束)在理论上应该是可行的,因为我们手动使用相同的约束集安排工作班次。我编写约束的方式有什么问题吗?

## looping over each worker
for j in range(N):
    ## looping for every Monday in the 28 days 
    for i in range(0,D,7):
        c = None
        ## accessing only the 5th and 6th work shift type 
        for k in range(4,T):
            c+=var[i][j][k]+var[i+1][j][k]+var[i+2][j][k]+var[i+3][j][k]+var[i+4][j][k]+var[i+5][j][k]+var[i+6][j][k]
        problem+= c==7

【问题讨论】:

    标签: optimization constraints linear-programming pulp


    【解决方案1】:

    如果我理解正确,那么您的约束要求每个工人每周都必须上第四班和第五班。这是因为c == 7,即c 中的7 个二进制文件必须设置为1。这不允许任何工人在0 到3 班工作,对吧?

    您需要更改约束,以便仅当工作人员在该范围内进行任何轮班时才强制执行c == 7。一个非常简单的方法是这样的

    v = list()
    for k in range(4,T):
      v.extend([var[i][j][k], var[i+1][j][k], var[i+2][j][k], var[i+3][j][k], var[i+4][j][k], var[i+5][j][k], var[i+6][j][k]])
    c = sum(v)
    problem += c <= 7        # we can pick at most 7 variables from v
    for x in v:
      problem += 7 * x <= c  # if any variable in v is picked, then we must pick 7 of them
    

    这绝不是最好的建模方法(指标变量会更好),但它应该让您知道该怎么做。

    【讨论】:

    • 感谢您的回复,不胜感激!也许我没有正确理解您的代码,但约束更接近(为清楚起见,删除了第 4 班和第 5 班警告):对于任何在 A 班工作的工人,他们必须整周都这样做(a.k.a var[i] [j][k], var[i+1][j][k], ..., var[i+6][j][k] 必须都等于 1,因为 k = A 如果有的话 = 1 首先是人 j)。不确定列表扩展在做什么。将不胜感激!
    • 嘿,我尝试实施该解决方案,并进行了一些更改,效果令人惊叹!仍然很想知道为什么啊啊
    • 好的,根据您更新的描述,我认为您只需将所有内容移动到k 循环中: 1. 构造与当前工作人员 shift A 对应的所有变量的列表 v和本周。 2.计算c = sum(v)。 3.添加problem += c &lt;= 7。 4.为v:for x in v: problem += 7 * x &lt;= c中的每个变量添加约束。我认为这应该在每个班次的基础上说明你的限制。诀窍是7 * x &lt;= c:如果至少有一个x 变量为1(即工人在本周工作A 班),那么c 中的所有变量都被强制为1。
    【解决方案2】:

    只是为了提供一种替代方法,假设(如我所读)在任何给定的一周内,工人可以在 7 天内以 [0:3] 的某种轮班组合工作,或者在其中一个轮班 [4: 5] 每天:我们可以通过定义一个新的二进制变量 Y[w][n][t] 来做到这一点,如果在第 w 周工作人员 n 执行受限班次 t,则该变量为 1,否则为 0。然后我们可以通过添加约束将该变量与我们现有的变量 X 关联起来,以便 X 可以取的值取决于 Y 的值。

    # Define the sets of shifts
    non_restricted_shifts = [0,1,2,3]
    restricted_shifts = [4,5]
    
    # Define a binary variable Y, 1 if for week w worker n works restricted shift t
    Y = LpVariable.dicts('Y', (range(round(D/7)), range(N), restricted_shifts), cat=LpBinary)
    
    # If sum(Y[week][n][:]) = 1, the total number of non-restricted shifts for that week and n must be 0
    for week in range(round(D/7)):
        for n in range(N):
            prob += lpSum(X[d][n][t] for d in range(week*7, week*7 + 7) for t in non_restricted_shifts) <= 1000*(1-lpSum(Y[week][n][t] for t in restricted_shifts))
    
    # If worker n has 7 restricted shift t in week w, then Y[week][n][t] == 1, otherwise it is 0
    for week in range(round(D/7)):
        for n in range(N):
            for t in restricted_shifts:
                prob += lpSum(X[d][n][t] for d in range(week*7, week*7+7)) <= 7*(Y[week][n][t]) 
                prob += lpSum(X[d][n][t] for d in range(week*7, week*7+7)) >= Y[week][n][t]*7
    

    一些示例输出(D=14,N=2,T=6):

            / M T W T F S S / M T W T F S S / M T W T F S S / M T W T F S S
    WORKER 0
    Shifts: / 2 3 1 3 3 2 2 / 1 0 2 3 2 2 0 / 3 1 2 2 3 1 1 / 2 3 0 3 3 0 3
    WORKER 1
    Shifts: / 3 1 2 3 1 1 2 / 3 3 2 3 3 3 3 / 4 4 4 4 4 4 4 / 1 3 2 2 3 2 1
    WORKER 2
    Shifts: / 1 2 3 1 3 1 1 / 3 3 2 2 3 2 3 / 3 2 3 0 3 1 0 / 4 4 4 4 4 4 4
    WORKER 3
    Shifts: / 2 2 3 2 1 2 3 / 5 5 5 5 5 5 5 / 3 1 3 1 0 3 1 / 2 2 2 2 3 0 3
    WORKER 4
    Shifts: / 5 5 5 5 5 5 5 / 3 3 1 0 2 3 3 / 0 3 3 3 3 0 2 / 3 3 3 2 3 2 3
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-09-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-07-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多