先不考慮工作之間的排假,要排最後再排就好。我們來觀察大A 和老G 兩人的 schedule,可以發現一個特性...
二、排程方法
由簡化後的目標可知,我們要找的排程 (schedule),上面的工作順序要跟期限順序相同。那麼解法就能簡單分成三個步驟:
- 將所有工作按 deadline 早晚排序
- 依序將排序好的工作,一次一個排入行程表
- 若排入的工作逾期,就從行程表中刪掉耗時最長的工作
一樣用上面的例子來演示
第一步,將所有工作按 deadline 排序為:
- 送餐 (7/3)
- 擦窗 (7/4)
- 掃地 (7/7)
- 洗碗 (7/8)
第二步、第三步一起做。依序將排序好的工作,一次一個排入行程表。若排入的工作逾期,就從行程表中刪掉耗時最長的工作。
排入第一個工作,送餐,沒有逾期。
排入第二個工作,擦窗,逾期了。
逾期了,那就刪掉行程表中最耗時的工作,剛好也是擦窗。
排入第三個工作,掃地,沒有逾期。
排入第四個工作,洗碗,沒有逾期。
四個工作都排完,最佳的排程就完成了!放棄擦窗,依序做了送餐、掃地、洗碗,三件工作。(需要在工作間請假的,可以輕鬆地以相反的順序洗、掃、送,以不造成逾期的前提下去規劃。)
話說,
不幸地(?),這個解跟大A 的一樣,而不是老G...,說好給自己一個成為老G 的機會,怎麼變大A 了?
因為我寫完文才發現圖畫反了= =
其實不用太在意,兩者都是最佳解...
結論
記重點就好,不論多少工作,只要符合本文 晚了就不要了 的情境,就能照這三個步驟:
- 將所有工作按 deadline 早晚排序
- 依序將排序好的工作,一次一個排入行程表
- 若排入的工作逾期,就從行程表中刪掉耗時最長的工作
找到最佳解。
附件
附上程式碼給有興趣的人參考,
但還沒 debug,有發現問題可以留言叫我修,或一起討論,教學相長!
schedule_case1.py
import datetime
import heapq
TODAY = '2023-07-01'
TASKS = [
('Clean Windows', 3, '2023-07-04'), # (task_name, days, deadline)
('Sweep Floor', 2, '2023-07-07'),
('Wash Dishes', 3, '2023-07-08'),
('Deliver Food', 1, '2023-07-03'),
]
# preprocess
today = datetime.date.fromisoformat(TODAY)
tasks = [(t[0], t[1], datetime.date.fromisoformat(t[2])) for t in TASKS]
# step 1, sort by deadline
tasks.sort(key=lambda task: task[2])
# step 2 and 3
schedule = []
begin_date = today + datetime.timedelta(days=1)
for task in tasks:
heapq.heappush(schedule, (-task[1], task))
begin_date += datetime.timedelta(days=task[1])
print('Add: ', task[0])
if (begin_date - datetime.timedelta(days=1) > task[2]):
removed_task = heapq.heappop(schedule)
begin_date = begin_date - datetime.timedelta(days=task[1])
print('Remove:', task[0])
# print schedule
begin_date = today + datetime.timedelta(days=1)
schedule.sort(key=lambda t: t[1][2])
print('My schedule:')
for task in schedule:
print(begin_date, 'start to:', task[1][0])
begin_date += datetime.timedelta(days=task[1][1])
執行結果 (理論上跟本文演示的例子會一樣)
$ python schedule_case1.py
Add: Deliver Food
Add: Clean Windows
Remove: Clean Windows
Add: Sweep Floor
Add: Wash Dishes
My schedule:
2023-07-02 start to: Deliver Food
2023-07-03 start to: Sweep Floor
2023-07-05 start to: Wash Dishes