###目次
GLPKによる勤務シフト表の作成1(1)(基礎編) (2) (3) ←ここ (4)
GLPKによる勤務シフト表の作成2 (2日連続して勤務する場合の勤務シフト)
デバッグ
モデル記述の中に
display 変数名;
を挿入することで変数の値が表示されます。
varだけではなくsetやparamで指定した名称も可能です。
さらなる改良版
スタッフが従事する時間帯や休みを確保するために、制約条件を追加してきましたが、varを宣言する時に変数の取り得る範囲を制限してしまって、従事する時は>=1に、休む時は<=0にすると、実現できます。
var assignShiftSchedule{(d,t) in BusinessHour, s in Staff} binary;
を
var assignShiftSchedule{(d,t) in BusinessHour, s in Staff} binary, >= if (d,t,s) in FixOnDuty then 1 else 0, <= if (d,t,s) in FixOffDuty then 0 else 1;
に変更して範囲指定、
不要になった
s.t. fix1{(d,t,s) in FixOnDuty}: assignShiftSchedule[d,t,s]=1;
s.t. fix2{(d,t,s) in FixOffDuty}: assignShiftSchedule[d,t,s]=0;
を取り除きます。
全体としては次のようになります。
# version 0.13
# シフト表作成
param firstDate; # 期間の最初の日付
param endDate; # 最後の日付
set Date := firstDate..endDate; # 期間内の日付
set TimeSlot := {"朝", "夕", "夜"}; # シフト時間枠
set Staff; # スタッフ名
param maxWorkingDays{Staff}; # 各スタッフの最大勤務日数
set BusinessHour dimen 2; # 営業時間帯
set FixOnDuty dimen 3; # 勤務時間帯
set FixOffDuty dimen 3; # 非番時間帯
# 日付,シフト時間枠,スタッフの配列を確保、出勤の割り当てで1が入る
var assignShiftSchedule{(d,t) in BusinessHour, s in Staff} binary, >= if (d,t,s) in FixOnDuty then 1 else 0, <= if (d,t,s) in FixOffDuty then 0 else 1;
# シフト時間枠に必ず1人従事
s.t. keepStaffInTimeSlot{(d,t) in BusinessHour}: sum{s in Staff}assignShiftSchedule[d,t,s]==1;
# 出勤は1日1回以下
s.t. avoidShiftPatten1{s in Staff, d in Date}: sum{(d,t) in BusinessHour}
assignShiftSchedule[d,t,s]<=1;
# 各スタッフの最大勤務日数で制限
s.t. restrictMaxWorkDays{s in Staff}: sum{(d,t) in BusinessHour}
assignShiftSchedule[d,t,s]<=maxWorkingDays[s];
# 連続勤務は3日以下
s.t. keepOffDay{s in Staff, d in firstDate..endDate-3}: sum{t in TimeSlot, d4 in d..d+3 : (d4,t) in BusinessHour}
assignShiftSchedule[d4,t,s]<=3;
# 翌日の勤務時間帯を制限
s.t. avoidShiftPatten2{s in Staff, d in firstDate..endDate-1}: sum{(d1, t) in {(d, "夕"), (d, "夜"), (d+1, "朝")} :(d1,t) in BusinessHour}
assignShiftSchedule[d1,t,s]<=1;
s.t. avoidShiftPatten3{s in Staff, d in firstDate..endDate-1}: sum{(d1, t) in {(d, "夜"), (d+1, "朝"), (d+1, "夕")} :(d1,t) in BusinessHour}assignShiftSchedule[d1,t,s]<=1;
solve;
# 出力
for{d in Date}{
printf "%2d ", d;
for{t in TimeSlot : (d,t) in BusinessHour}{
printf{s in Staff : assignShiftSchedule[d,t,s]==1}" %s", s;
}
printf "\n";
}
data;
# 期間の最初の日付と最後の日付
param firstDate:=1;
param endDate :=13;
# スタッフ名と最大勤務日数
param : Staff : maxWorkingDays :=
"A" 9
"B" 9
"C" 9
"D" 9
;
# 営業時間帯
set BusinessHour :=
(1, *) "朝" "夕" "夜"
(2, *) "朝" "夕" "夜"
(3, *) "朝" "夕" "夜"
(4, *) "朝" "夕" "夜"
(5, *) "朝" "夕" "夜"
(6, *) "朝" "夕"
# 7日は休業
(8, *) "朝" "夕" "夜"
(9, *) "朝" "夕" "夜"
(10, *) "朝" "夕" "夜"
(11, *) "朝" "夕" "夜"
(12, *) "朝" "夕" "夜"
(13, *) "朝" "夕"
;
# スタッフが従事する時間帯を指定
set FixOnDuty :=
(1, "朝", "A")
(1, "夕", "B")
(1, "夜", "C")
;
# スタッフが出勤できない時間帯を指定
set FixOffDuty :=
(2, *, "A") "朝" "夕" "夜"
(3, *, "B") "朝" "夕" "夜"
;