簡體   English   中英

線性規划中的連續天數約束

[英]consecutive days constraint in linear programming

對於輪班優化問題,我在 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

如果我理解正確,那么您的約束要求每個工人每周都必須上第四班和第五班。 這是因為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

這絕不是 model 的最佳方法(指標變量會好得多),但它應該讓您知道該怎么做。

只是為了提供一種替代方法,假設(如我所讀)在任何給定的一周內,工人可以在 7 天內以 [0:3] 的輪班組合工作,或者每個輪班 [4:5] day:我們可以通過定義一個新的二進制變量 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

一些示例 output(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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM