看護学部の実習先を割り当てる問題です。実習先を一つのシフトとして表現します。
シフト定義としては、成人1
成人2
老年
地域
精神
小児
母性
統合
があります。期間60日内に上記シフトを割り当てます。シフトは、連続的であり、期間内に一回です。例えば、上の解では、成人1が3日、成人2が3日になっていますが、これらは、期間内に一回となっています。こういった連続シフト島をシフト連と呼称し、シフト連毎に順番の制約がある問題をシフト連問題と呼ぶことにします。
<シフト連問題は、何が問題か?>
シフト連毎に順番があることが問題です。看護師である妻に聞いたところ、たとえば、「成人1の前に、成人2は、有り得ない」、「統合は、まあ最後かな。 」という具合に、シフト連毎にハード制約とソフト制約が存在するようです。Day単位ならば、GUIでシフトパターンとして記述が可能ですが、不定長の連なので、GUIでは記述が困難です。
<難易度>
Pythonで制約を記述しますので、上級です。私も数十分悩んだのでアルゴリズムの難易度は高いです。加えて、GUIで操作インターフェースをどのようにPythonで記述するか?という問題もあります。やはり難易度が高いです。
<アルゴリズム>
便宜的にA>BをAは、Bに先行すると表記します。シフトA、BがあったときA>Bを実現するには、次のように、簡単な2日間から出発し、n日間では、どういう制約が必要になるかを考えてみます。
すると、期間をありえる全ての2つに分けて禁止パターンを記述していけばよいことに気づきます。ちなみに一つの連の長さは不定で、期間内に1個のみという仕様です。禁止パターンで記述しておけば、連が存在しないときでも悪さはしません。あくまで全てのB>Aを禁止するだけです。60日期間であれば、59個の禁止パターンを制約することになります。
<連の記述>
連は、期間内に1個なので、各Person,各DayでORを取れば十分です。
まずは、成人1>成人2 制約を記述してみます。
僅か24行です。import sc3 def 順序(): first_day=今月[0] #期間初日 last_day=今月[len(今月)-1] #期間最終日 for person in 全グループ:#全ての人について st=staffdef[person]+' 順序制約' sc3.print(st+'します。\n') for day in 今月:#全期間あらゆる分割を行う vlist2=[] vlist1=[] for d in range(first_day,day+1):#初日からday日まで v2=sc3.GetShiftVar(person,d,'成人2')#person day shiftで状態取得 Binary 0/1 vlist2.append(v2) for d in range(day+1,last_day+1):#day+1日から最終日まで v1=sc3.GetShiftVar(person,d,'成人1')#person day shiftで状態取得 Binary 0/1 vlist1.append(v1) V2=sc3.Or(vlist2)#成人2連を求める V1=sc3.Or(vlist1)#成人1連を求める st_day=st+' '+ str(day) sc3.AddHard(~(V2&V1),st_day) #成人2>成人1 を禁止する。ハード制約する 順序()
<Pythonを書くときの注意点>
■いつものように設定ボタンを押すのを忘れずに。また、前のソースに戻ってしまう現象が起こることがあります。RUNする前に保存も行ってください。
■インデント自体に意味があります。インデントを揃えてください。下記は、インデントエラーの例です。赤いところをダブルクリックします。
すると、ソース全体に飛んでいきます。インデントが揃っていないことがわかります。
0 件のコメント:
コメントを投稿