Pythonで受け入れられる招待状の数を求めるプログラム ― DFSによる二部グラフマッチング
パーティーの準備で、m人の男子とn人の女子がいるとします(m = n)。各男子は必ず女子を一人連れて参加しなければならず、男子たちは全員が女子に招待状を送ります。ただし、各女子が受け入れられる招待状は一通だけです。このとき、女子が実際に受け入れられる招待状の総数を求めます。
入力はm × nの行列として与えられ、セル(i, j)は「男子iが女子jに招待状を送ったかどうか」を表します。値が1なら招待状を送ったこと、0なら送っていないことを意味します。
入力例
| 1 | 0 | 0 |
| 1 | 0 | 1 |
| 1 | 1 | 0 |
この場合の出力は3になります。
- 女子1が男子1の招待状を受け入れる
- 女子2が男子3の招待状を受け入れる
- 女子3が男子2の招待状を受け入れる
(ここではインデックスは1から始まるものとします)
解き方のアプローチ
この問題は「二部グラフの最大マッチング」問題として捉えることができます。男子と女子をそれぞれ頂点とみなし、招待状を辺とみなすと、受け入れられる招待状の最大数は最大マッチングのサイズに一致します。
これを解くには、DFS(深さ優先探索)を使って増加道(オーギュメンティングパス)を見つける手法が有効です。手順は以下の通りです。
- dfs(node, seen) 関数を定義する。
- nei を 0 から N-1 まで繰り返す:
- grid[node][nei] が 0 以外で、かつ seen[nei] が False の場合:
- seen[nei] := True
- matching[nei] が -1 である、または dfs(matching[nei], seen) が True の場合:
- matching[nei] := node
- True を返す
- grid[node][nei] が 0 以外で、かつ seen[nei] が False の場合:
- False を返す
- nei を 0 から N-1 まで繰り返す:
- M := grid の行数
- N := grid の列数
- matching := サイズ N のリスト(すべて -1 で初期化)
- res := 0
- i を 0 から M-1 まで繰り返す:
- seen := サイズ N のリスト(すべて False で初期化)
- dfs(i, seen) が True の場合: res += 1
- res を返す
実装例
以下のPythonコードで実際の動作を確認できます。
def solve(grid):
M, N = len(grid), len(grid[0])
matching = [-1] * N
def dfs(node, seen):
for nei in range(N):
if grid[node][nei] and not seen[nei]:
seen[nei] = True
if matching[nei] == -1 or dfs(matching[nei], seen):
matching[nei] = node
return True
return False
res = 0
for i in range(M):
seen = [False] * N
if dfs(i, seen):
res += 1
return res
print(solve([[1, 0, 0], [1, 0, 1], [1, 1, 0]]))
入力
[[1, 0, 0], [1, 0, 1], [1, 1, 0]]
出力
3
計算量について
各男子ごとにDFSを1回実行する構成のため、このアルゴリズムの時間計算量は一般的にO(V・E)(Vは頂点数、Eは辺数)と評価されます。人数がそれほど多くない場合は十分に高速に動作し、競技プログラミングなどでも広く使われる定番の手法です。
-
Pythonで倉庫(godown)に押し込めるボックスの数を求めるプログラム
問題の概要 2つの整数配列が与えられていると仮定しましょう。一方のリストには単位幅のボックスの高さが、もう一方の配列には倉庫(godown)内の各部屋の高さが格納されています。部屋には 0〜n の番号が付いており、各部屋の高さは godown 配列の対応するインデックスに記録されています。ここで、倉庫に押し込むことのできるボックスの数を求めます。 ただし、以下のルールを守る必要があります。 ボックスを積み重ねることはできません。 ボックスの順序は自由に入れ替えられます。 ボックスは必ず左から右へ向かって挿入します。 もしボックスの高さがある部屋の高さより大きい場合、そのボックスおよびそれよ
-
Pythonでリスト内の最小値を見つける方法を解説
この記事では、リストの中から最小の数値を見つける方法について、具体的なサンプルコードとともに詳しく解説します。問題の概要問題: 数値のリストが与えられたとき、その中に含まれる最も小さい数値を画面に表示すること。この問題を解くアプローチは主に2つあります。ひとつは sort() メソッドを使ってリストを昇順に並べ替え、先頭の要素(インデックス0)を取得する方法。もうひとつは、Pythonに標準で用意されている組み込み関数 min() を使う方法です。それぞれ順番に見ていきましょう。方法1:sort()メソッドで並べ替えて最小値を取得するまずはリストを昇順にソートし、先頭の要素を取り出す方法です。