■土日夜勤の場合、公休が2日取得となりますが そのうち1日は必ず「1か月を3分割し、そのWindow以内に公休を消化する」にし、もう1日は同月内であれば、いつでも良いとする。もちろん、金土夜勤の場合、日月夜勤の場合は今まで通り「1か月を3分割し、そのWindow以内に公休を消化する」こととする。
■仕様の背景は、理解していません。とりあえず、実装し易い形に変形しています。 以下をPythonで実装しています。 土日夜勤した場合10日Window内で公休を1日取得2日ある場合はその月内でもう1日取得()
ここでの、ポイントは、公休(代休)が取得される論理です。例えば、A Window期間中に土日のどちらか夜勤があれば、A Window中、公休は必ず1個取得されます。これが、Ac==Aa|Ab 部になります。さらに、B Window中に土日連続夜勤があったとき(Bab) A Window で公休が発生するというロジックです。夜勤数、公休数共に、2個以下に制限してあるので、この条件が発生するのはAc==Babでしか起こりえません。 また、公休が発生しないのは、(Aa|Ab|Bab) のどれも該当しない、つまり夜勤が発生しないときは、公休を生成させないということに符合します。 ということで、簡単なロジックで、必要にして十分、つまり同値であることが判ります。同値のルーチンは、前々回に説明しました。また、Acや、Acは、ΣXi>=1 という関係です。これは、前回説明しました。それぞれのWindow内でORを取ればよいことが判ります。 同様にして、他のWindowも処理できます。 かなり複雑な仕様ですが、Pythonで100行足らずで記述できました。かなり難しい部類のプログラムだと思いますが、SeqCompや、SeqExpr等の制約関数を使っていないので、性能的にもMaxになっているはずです。
a:土夜 b:日夜
c:公休(土日以外)
A:Window1 B:Window2 C:Window3
Ac== (Aa| Ab |Bab)
Bc== (Ba| Bb |Cab)
Cc== (Ca| Cb |Aab)
Σ(a|b)<=2 今月
Σc<=2 今月
def 等号制約(a,b,s): sc3.AddHard( (a|~b) &(~a|b),s) def 代休window処理_v2(person,window): holiday_domain=[] sat_sun=[] ss=[] for day in window: if day in 土 or day in 日: sat_sun.append(day) else: holiday_domain.append(day) if day in 土 and day+1 in window: ss.append(day) vreturn_list=[] vsat_sun=[] vholidays=[] vssdays=[] for day in ss: #sc3.print('土'+str(day)+'\n') v1=sc3.GetShiftVar(person,day,'入り')# v2=sc3.GetShiftVar(person,day+1,'明け') vssdays.append(v1&v2)#土日連続夜勤 for day in sat_sun: #sc3.print('土'+str(day)+'\n') v1=sc3.GetShiftVar(person,day,'入り')# v2=sc3.GetShiftVar(person,day,'明け') vsat_sun.append(v1|v2)#土日に夜勤 for day in holiday_domain: #sc3.print('H'+str(day)) v1=sc3.GetShiftVar(person,day,'公休')# vholidays.append(v1)#公休 s=staffdef[person]+daydef[day]+'代休処理' #sc3.AddSoft(sc3.SeqComp(vsat_sun,vholidays),s,7) vreturn_list.append(sc3.Or(vsat_sun)) vreturn_list.append(sc3.Or(vholidays)) vreturn_list.append(sc3.Or(vssdays)) return vreturn_list def 土日夜勤した場合10日Window内で公休を1日取得2日ある場合はその月内でもう1日取得(): 今月日数=len(今月) WindowDays=今月日数/3 #3分割 win1=[] win2=[] win3=[] for day in 今月: if len(win1)< WindowDays: win1.append(day) elif len(win2)< WindowDays: win2.append(day) else: win3.append(day) sc3.print('window1=',str(len(win1))+'\n') sc3.print('window2=',str(len(win2))+'\n') sc3.print('window3=',str(len(win3))+'\n') #今月で見たときに土日出勤数==公休数とする sat_sun=[] holiday_domain=[] for day in 今月: if day in 土 or day in 日: sat_sun.append(day) else: holiday_domain.append(day) for person in 夜勤可能: vsat_sun=[] vholidays=[] vlist1=代休window処理_v2(person,win1)#Window内では1日に限定 vlist2=代休window処理_v2(person,win2)#Window内では1日に限定 vlist3=代休window処理_v2(person,win3)#Window内では1日に限定 for day in sat_sun: #sc3.print('土'+str(day)+'\n') v1=sc3.GetShiftVar(person,day,'入り')# v2=sc3.GetShiftVar(person,day,'明け') vsat_sun.append(v1|v2) for day in holiday_domain: #sc3.print('H'+str(day)) v1=sc3.GetShiftVar(person,day,'公休')# vholidays.append(v1) s=staffdef[person]+daydef[day]+'今月処理' sc3.AddHard(sc3.SeqLE(0,2,vsat_sun),s+'土日')#土日夜勤は2回以内 sc3.AddHard(sc3.SeqLE(0,2,vholidays),s)#公休2回以内 等号制約(vlist1[0]|vlist2[2],vlist1[1],'Ac==(Aa|Ab|Bab)') 等号制約(vlist2[0]|vlist3[2],vlist2[1],'Bc==(Ba|Bb|Cab)') 等号制約(vlist3[0]|vlist1[2],vlist3[1],'Cc==(Ca|Cb|Aab)')
0 件のコメント:
コメントを投稿