【具体例で実演!】人材配置の最適化問題をエクセルマクロVBAを使って解いてみた

2021年7月26日

ある物流センターでは、物流加工で4つの工程があります。

各工程1人ずつで受け持ち、毎日合計4人必要です。

今まで延べ7人がこの作業を行ったことがあり、各人の作業生産性(個/時間)と時給は次の通りです。

 

センター長は、そろそろスタッフを固定したいと思っています。

全体の生産性は一番生産性の悪い工程(ボトルネック)で決まります。

この時、全体の生産性を70以上にしながら、総時給が7,000円以内に抑えられるようにするには、どの工程に誰を割り当てたら良いでしょうか?

 

順列の数は?

例えば、工程Aを鈴木さん、工程Bを高橋さん、工程Cを渡辺さん、工程Dを田中さんに割り当てる場合を考えてみましょう。

 

工程Bの生産性が70で一番低いため、全体の生産性は工程Bに制約されて70になります。

一方、4人の総時給は2,000+2,090+1,800+1,940=7,830円となります。

従って、この順列では生産性は70をクリアしますが、総時給は7,000円を上回ってクリアしません

 

すべての順列は7×6×5×4=840通りありますので、これらすべてについて生産性と総時給を計算するとなると、人手ではとんでもない時間がかかってしまいます。

>> 順列と組み合わせ

 

変数に数字を読み込む

こんな時に力を発揮するのがエクセルマクロです。

7個の中から4個を選ぶ順列をマクロで列挙する方法については、前回の記事で解説しました。

>> エクセルマクロで順列と組み合わせを列挙する

 

今回はこのマクロに少しプログラムを追加して、この問題を解いてみます。

 

まず、先ほどの生産性や人件費の表の数値を変数としてマクロに読み込みます。

すべての数字に変数を割り当てようとすると、35も変数を定義しないといけなくて面倒です。

そこで、配列という考え方を使います。

普通は一つの変数は一つの数字しか取れないのですが、配列で変数を定義すると複数の数字を入れられます。

そこで、次のように5つの変数を配列で定義します。

 

このようにすると、PA(1)には31を、PA(2)には74、、、を入れられるようになります。

では、この表の35個の数字を5つの変数に読み込むプログラムを書いてみましょう。

次のようになります。

For I = 1 To 7

PA(I) = Range(Cells(I + 3, 3), Cells(I + 3, 3))

PB(I) = Range(Cells(I + 3, 4), Cells(I + 3, 4))

PC(I) = Range(Cells(I + 3, 5), Cells(I + 3, 5))

PD(I) = Range(Cells(I + 3, 6), Cells(I + 3, 6))

Cost(I) = Range(Cells(I + 3, 7), Cells(I + 3, 7))

Next I

 

たったこれだけで、35個の数字を5つの変数に読み込めます。

 

条件にマッチする順列を探す

前回の記事で、7個から4個を選ぶすべての順列を変数a1~a4に書き出しました。

(a1~a4の組み合わせは840通り

これは、a1~a4工程A~Dと読み替えると、どの工程に7人のうちの誰を割り当てるかということと同じです。

例えば、a1=1、a2=2、a3=3、a4=4の順列だと、工程Aに佐藤さん、工程Bに鈴木さん、工程Cに高橋さん、工程Dに田中さんを割り当てることに相当します。

 

この場合、

PA(a1)は佐藤さんの工程Aの生産性=31

PB(a2)は鈴木さんの工程Bの生産性=70

PC(a3)は高橋さんの工程Cの生産性=75

PD(a4)は田中さんの工程Dの生産性=76

Cost(a1)は佐藤さんの時給=1,300

Cost(a2)は鈴木さんの時給=2,000

Cost(a3)は高橋さんの時給=2,090

Cost(a4)は田中さんの時給=1,800

ですので、

全体の生産性=31(31、70、75、76の中で一番低い値)

総時給=7,190

ということが計算できます。

 

マクロで書くと次のようになります。

If SS = 0 Then

CBN = a1 & a2 & a3 & a4

P = WorksheetFunction.Min(PA(a1), PB(a2), PC(a3), PD(a4))

C = WorksheetFunction.Sum(Cost(a1), Cost(a2), Cost(a3), Cost(a4))

If P > 70 And C < 7500 Then

XX = XX + 1

Range(Cells(XX + 1, 1), Cells(XX + 1, 1)) = CBN

Range(Cells(XX + 1, 2), Cells(XX + 1, 2)) = P

Range(Cells(XX + 1, 3), Cells(XX + 1, 3)) = C

Else

End If

End If

 

赤字の箇所で4人の生産性の最小値を、青字の箇所で4人の総時給を計算しています。

そして、緑字の箇所で全体の生産性が70以上、かつ総時給が7,000円以下のパターンだけを選んでいます。

選ばれた順列だけが、シートに順に書き込まれます。

 

このマクロを実行すると、次のように条件にマッチする8つの順列がシートに書き込まれます。

 

840通りの順列の中で、条件にマッチするのは8つだけでした。

中でも一番コスパが良さそうなのは、下から2番目の順列、工程Aが渡辺さん、工程Bが田中さん、工程Cが山本さん、工程Dが佐藤さんの時で、その時の総時給は6,690円になります。

 

これを人手で計算するとなると気の遠くなる作業で、普通の人は諦めるでしょう。

でも、マクロを使いこなせれば不可能が可能になるのです。

 

まとめ

実はこの計算、マクロでやらせても10くらい時間がかかります。

もっと計算負荷が低いやり方で、うまくプログラムを組んだとしても5分以上はかかると思います。

 

このようなのを組み合わせ最適化問題と言いますが、nが大きくなると爆発的に計算負荷が増えます。

この例だと7個の中から4個を選ぶ順列ですが、10個の中から7個を選ぶ順列になると、実に4,000くらいの時間がかかります。

今後、量子コンピュータでブレークスルーが期待されている分野です。

 

でも、エクセルマクロでやっても、人手でやるとまず不可能なことが可能なレベルにはなります。

私は10時間くらいかかるプログラムを走らせて、組み合わせ最適化問題を解いたことがありました。

その時は、誰も考えていなかった意外な組み合わせが最もコスト安となることが分かって、皆に驚かれました。

意外と、あなたの身の周りにもそのような未解決問題があるかもしれませんよ。