■土日夜勤の場合、公休が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 件のコメント:
コメントを投稿