クリーム色の背景、色付き表示、高コントラスト、大きな文字のほうが読みやすいですか?配色と文字を選ぶと、すべてのページに一度で反映されます。

無料レッスン

割り当て問題と輸送問題

このレッスンのあとで: 小さな割り当て問題を、全部の組み合わせを試して解くことができる。

60分のレッスンコマンド4件JupyterLab データサイエンスラボ:pandas、Matplotlib、scikit-learn をブラウザーで

誰がどの地区を回るか

割り当て問題とは、人と仕事を1対1で組み合わせ、費用の合計をいちばん小さくする問題です。配達員と地区を結ぶ場合のように、組み合わせが少なければ、全部試して答えが出ます。

数が増えたときの速い解き方も、このレッスンで見ます。

このレッスンのゴール

メモ

小さな割り当て問題を、全部の組み合わせを試して解くことができる。

キーワード

ことばいみれい
割り当て問題人と仕事を1対1で結び、費用の合計を最小にする問題
費用の表人と仕事の組ごとの費用を並べた表
階乗1からその数までを全部かけた数3の階乗は6
貪欲法目の前でいちばん安いものを順に選ぶ方法
輸送問題工場から店へ、運ぶ量と費用を決める問題

学生が入力するセルは、このプレビューでは空白です。

費用の表で、割り当てを考える

配達員のA、B、Cの3人が、3つの地区を1つずつ受け持ちます。表の数字は、その人がその地区を回る分数です。

合計の分数がいちばん小さくなる組み合わせを探します。1人が2つの地区を受け持つことはできません。

配達にかかる分数

配達員地区0地区1地区2
A927
B643
C581

学生が入力するセルは、このプレビューでは空白です。

全部試せば、必ず最小が見つかる

3人なら、組み合わせは6通りしかありません。全部の合計を出し、いちばん小さいものを選べば、それが最適です。

次の表は、6通りの合計です。最小は9分で、Aが地区1、Bが地区0、Cが地区2を回る組み合わせです。

6通りの合計

A、B、Cの地区費用の合計
0、1、29 + 4 + 1 = 14
0、2、19 + 3 + 8 = 20
1、0、22 + 6 + 1 = 9
1、2、02 + 3 + 5 = 10
2、0、17 + 6 + 8 = 21
2、1、07 + 4 + 5 = 16

学生が入力するセルは、このプレビューでは空白です。

6通りを全部試して最小を出す

コマンド
docker exec jupyter python3 -c "from itertools import permutations; C = [[9, 2, 7], [6, 4, 3], [5, 8, 1]]; print(min(sum(C[i][p[i]] for i in range(3)) for p in permutations(range(3))))"

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

組み合わせを全部書き出す

コード: python
# 3人を3つの地区に割り当てる全部の組み合わせを、費用つきで表示します。
cost = [[9, 2, 7], [6, 4, 3], [5, 8, 1]]
for a in range(3):
    for b in range(3):
        for c in range(3):
            if a != b and a != c and b != c:
                total = cost[0][a] + cost[1][b] + cost[2][c]
                print(a, b, c, "合計", total)
# cost の数字を変えて、いちばん小さい合計が変わるか確かめてください。

人数が増えると、全部試せなくなる

n人のときの組み合わせは、nの階乗です。3人は6通り、5人は120通り、10人は約363万通りに増えます。

20人になると、約243京通りです。全部試す方法は、人数が少ないときだけの方法です。

人数と組み合わせの数

人数組み合わせの数
3人6
5人120
8人40320
10人3628800
15人1307674368000

学生が入力するセルは、このプレビューでは空白です。

10人と15人の組み合わせの数

コマンド
docker exec jupyter python3 -c "import math; print(math.factorial(10), math.factorial(15))"

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

よくある間違い

注意

多くの人は、各人が自分にいちばん安い地区を順に取れば、合計も最小になると考えます。この表では、Aが2、Bが3、Cが5で合計10になり、最小の9より大きくなります。目の前の安さだけでは、全体の最小になりません。

速い解き方と、輸送問題

SciPy の linear_sum_assignment は、割り当て問題を速く解きます。20人でも一瞬です。

輸送問題は、工場から店へ運ぶ量を決めます。各工場の供給と、各店の需要を守りながら、費用の合計を最小にします。linprog で解けます。

速い解き方で、同じ答えを出す

コマンド
docker exec jupyter python3 -c "import numpy as np; from scipy.optimize import linear_sum_assignment as lsa; C = np.array([[9, 2, 7], [6, 4, 3], [5, 8, 1]]); r, c = lsa(C); print(c, C[r, c].sum())"

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

輸送問題の例(100円単位)

工場と店店P店Q供給
工場A4630箱
工場B5320箱
需要25箱25箱

学生が入力するセルは、このプレビューでは空白です。

輸送問題を解く

コマンド
docker exec jupyter python3 -c "from scipy.optimize import linprog; r = linprog([4, 6, 5, 3], A_eq=[[1, 1, 0, 0], [0, 0, 1, 1], [1, 0, 1, 0], [0, 1, 0, 1]], b_eq=[30, 20, 25, 25]); print(round(r.fun, 2), r.x)"

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

さらに挑戦: 費用を変える

費用の表の数字を1つ変えて、最小の組み合わせがどう変わるかを調べてください。たとえば、Aの地区1を2から9に変えます。

すると、最小の合計と、組み合わせの両方が変わります。数字を変えるたびに、全部試す方法で確かめましょう。

このラボとソースについて: JupyterLab データサイエンスラボ:pandas、Matplotlib、scikit-learn をブラウザーで

授業で使いますか?このモジュールを学生に割り当てると、教員用ガイド、自動採点つきの課題、学生ごとのラボを使えます。