[アルゴリズム解説] シフト・スケジューリング問題(バイトのシフト作成、面倒から卒業する方法)
どうも、mikanecoです。
みなさんバイトやお店のシフト組み、やったことありますか?
「責任者を必ず1人以上入れる」とか、「開店時には鍵を持ってる人が必要」とか、「あの2人はやらかすから絶対一緒に入れないで」みたいな細かいルールが山ほど出てきて、正直めちゃくちゃ面倒ですよね。
でも、これらの条件や制約を“数理モデル”として整理すると、自動でシフトが組めるようになるんです。今回はそんな「面倒なシフト作成を自動化するアプローチ」と「実際のコード例」まで紹介します。
1. シフト作成って何が大変なの?
まずは現実に起こる“めんどくさい”シフト作成の課題を整理します。ざっくり、以下みたいなやつです。
ケース1:責任者の配置
- 各シフトに必ず1人以上責任者が必要。でも責任者が少ないと偏って負担が大きくなるので、バランスよく割り振りたい。
ケース2:組み合わせNG
- 過去にトラブルがあった2人(例:松本さんと浜田さん)は同じシフトに入れないようにしたい。
ケース3:鍵を持つ人の配置
- 開店時に“鍵”を持った人が必ず必要。もし1人しかいないなら、その人のシフト調整が特に重要。
ケース4:勤務時間の制約
- 週○時間以上働かせたい・働かせたくない、フルタイム/パートの区分、休憩時間の確保など。いろんな時間的な制約もクリアしなきゃいけない。
これら全部を“手作業”でやるのは地獄ですが、数理モデルで整理すれば機械的に解ける問題に変わります。
2. 数理モデルってなに?どう使う?
“数理モデル”とは、現実のルールや条件を「変数」や「数式」で表すことです。
例えば…
- 責任者を必ず1人以上入れる → 「各シフトの責任者数 >= 1」という条件を数式で書く。
- AさんとBさんは一緒に入れない → 「AとBが同じシフトのとき、その割り当ては不可」とする。
- 鍵を持つ人を開店時に配置 → 「開店シフトに鍵スタッフが1人以上」
こうやって全部の条件を“制約条件”として列挙し、「このルール全部守って、一番バランスのいいシフトを自動で作って!」という命令を出せるのが数理最適化の強み。
制約条件を全部並べてみる
- 各シフトに責任者を1人以上含める
- NG組み合わせは同じシフトにしない
- 鍵を持つ人を開店時に入れる
- 勤務時間の上下限を守る
これらをコード(数理モデル)に落とし込めば、あとは自動計算です。
シフト作成の基本フロー
- 入力データを準備(勤務可能時間、NGペア、責任者リストなど)
- 制約条件をすべて列挙
- 「なるべく希望が叶う」「バランスが良い」などの目的関数を決める
- 適したアルゴリズムを選ぶ(線形計画法・整数計画法など)
- 出力されたシフト案を微調整
3. 実際のアルゴリズムの作り方
大まかな流れはこんな感じです。
-
データ準備
- 従業員ごとの勤務可能時間
- 責任者リスト
- NG組み合わせ
- 鍵を持つ人リスト
- 各自の勤務時間制約
-
制約条件の整理
- 例:各シフトに責任者が1人以上/NGペアは同じシフト不可/鍵持ちは開店に必須…など
-
目的関数を決める
- 希望シフトを最大限叶えたい、責任者の負担を分散したい、など
-
アルゴリズム選定&実装
- 線形計画法(LP)、整数計画法(IP)、遺伝的アルゴリズム(GA)など
-
結果を確認・微調整
- 出力シフトをチェックし、必要なら条件やパラメータを調整
-
さらに最適化
- 実運用で得られた知見をもとに随時改善
4. Pythonでの実装例(Google OR-Tools)
実際にPython+Google OR-Toolsでシフト割り当てを最適化してみます。
問題設定
-
従業員A・B・C
-
シフトは「早番」「中番」「遅番」
-
条件:
- 各シフト1人ずつ
- Aは遅番NG
- Bは1日2回以上シフトに入らない
- Cは早番必須
インストール
pip install ortools
コード
from ortools.sat.python import cp_model
# モデル作成\model = cp_model.CpModel()
employees = ['A', 'B', 'C']
shifts = ['early', 'mid', 'late']
assignment = {}
for e in employees:
for s in shifts:
assignment[(e, s)] = model.NewBoolVar(f'{e}_{s}')
# 各シフト1人
for s in shifts:
model.Add(sum(assignment[(e, s)] for e in employees) == 1)
# Aは遅番NG
model.Add(assignment[('A', 'late')] == 0)
# 各従業員1日1回まで
for e in employees:
model.Add(sum(assignment[(e, s)] for s in shifts) <= 1)
# Cは早番必須
model.Add(assignment[('C', 'early')] == 1)
solver = cp_model.CpSolver()
status = solver.Solve(model)
if status == cp_model.OPTIMAL:
for s in shifts:
for e in employees:
if solver.Value(assignment[(e, s)]) == 1:
print(f'{e} is assigned to {s} shift.')
else:
print("No optimal solution found.")
結果例
C is assigned to early shift.
B is assigned to mid shift.
A is assigned to late shift.
すべての制約条件を満たした最適なシフトが一発で計算されます。
まとめ
数理モデル×最適化アルゴリズムを使えば、「責任者を均等に配置」「組み合わせNGを守る」「開店時に鍵を必ず配置」「勤務時間をバランス良く分配」など、現場の“めんどくさいシフト作成”を一気に自動化できます。
従業員やシフトの数・制約条件を増やしても、同じ手法で対応可能。ルールが増えるほど「自動化の価値」は高まります。シフト作成の面倒に悩んでる人は、ぜひこのやり方を試してみてください!
Discussion