Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

GLPKによる勤務シフト表の作成1(3)

More than 3 years have passed since last update.

目次

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;
を取り除きます。

全体としては次のようになります。

shift3.model
# 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") "朝" "夕" "夜"
;

GLPKによる勤務シフト表の作成1(4)->

ki073
業務の手抜き?をできるようにRubyやRを中心に使っています。今は高速化をねらってHaskellにも手を出しています。最適化問題で困っている人が多いので最近ではGLPKのプログラムを多く公開しています。質問や要望などがありましたらコメント欄に書き込んでください。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away