Pythonで全てのボールを各ボックスに集めるための最小操作回数を求めるプログラム
問題の概要
「boxes」というバイナリ文字列(0と1のみで構成される文字列)があるとします。boxes[i] が '0' の場合は i 番目のボックスが空であることを、'1' の場合はそのボックスにボールが 1 個入っていることを意味します。
1 回の操作では、あるボックスから隣接するボックスへボールを 1 個移動できます。操作の結果、1 つのボックスに複数のボールが入っても構いません。ここで、サイズ n の配列 answer を求めます。answer[i] は、すべてのボールを i 番目のボックスに集めるために必要な最小操作回数です。
たとえば、入力が boxes = "1101" の場合、出力は [4, 3, 4, 5] となります。
- 1 番目のボックスに集める場合:2 番目のボックスから 1 操作、最後のボックスから 3 操作が必要なため、合計 4 操作。
- 2 番目のボックスに集める場合:1 番目のボックスから 1 操作、最後のボックスから 2 操作が必要なため、合計 3 操作。
- 3 番目のボックスに集める場合:2 番目と最後のボックスからそれぞれ 1 操作、1 番目のボックスから 2 操作が必要なため、合計 4 操作。
- 最後のボックスに集める場合:1 番目のボックスから 3 操作、2 番目のボックスから 2 操作が必要なため、合計 5 操作。
解決のためのアプローチ
各ボックスごとに毎回距離を計算し直す素朴な方法では O(n²) の計算量が必要ですが、累積和の考え方を使えば O(n) で効率的に解けます。手順は以下のとおりです。
- left := 0、right := 0、dist := 0 で初期化します。
- i を 0 から boxes の長さ - 1 まで繰り返します。
- boxes[i] が "1" の場合:dist := dist + i とします(インデックス 0 までの距離の合計)。さらに、i が 0 なら left を 1 増やし、そうでなければ right を 1 増やします。
- dist を初期値とするリスト arr を作成します。
- i を 1 から boxes の長さ - 1 まで繰り返します。
- arr[i-1] + left - right を arr の末尾に追加します。
- boxes[i] が "1" の場合:left を 1 増やし、right を 1 減らします。
- arr を返します。
このアルゴリズムが機能する理由
注目位置を 1 つ右にずらすとき、左側にあるボールはすべて 1 操作ずつ遠ざかり、右側(現在位置以降)にあるボールはすべて 1 操作ずつ近づきます。したがって、前の答えに「left(左側のボール数)− right(右側のボール数)」を加算するだけで次の答えが求まります。ボールを通過するたびに left と right のカウントを更新すれば、配列全体を線形時間で処理できます。
実装例
理解を深めるために、以下の実装を見てみましょう。
def solve(boxes):
left = 0
right = 0
dist = 0
for i in range(len(boxes)):
if boxes[i] == "1":
dist += i
if i == 0:
left += 1
else:
right += 1
arr = [dist]
for i in range(1, len(boxes)):
arr.append(arr[i-1] + left - right)
if boxes[i] == "1":
left += 1
right -= 1
return arr
boxes = "1101"
print(solve(boxes))入力
"1101"
出力
[4, 3, 4, 5]
-
Pythonで全ての点を接続するための最小コストを求めるプログラム
問題の概要(x, y) の形式で表される複数の点が格納された配列 points があるとします。2つの点 (xi, yi) と (xj, yj) を接続するコストは、それらの間のマンハッタン距離として定義されます。マンハッタン距離は次の式で計算できます。|xi − xj| + |yi − yj|この問題では、すべての点を接続するために必要な最小のコストを求める必要があります。入力例points = [(0,0), (3,3), (2,10), (6,3), (8,0)]この場合、出力は 22 になります。これは、各辺の距離がそれぞれ 6 + 5 + 3 + 8 = 22 となるように点同士を接
-
Pythonで全ノードに到達可能な最小の頂点集合を見つけるプログラム
問題概要有向非巡回グラフ(DAG)を考えます。グラフにはn個の頂点があり、各ノードには0からn-1までの番号が付けられています。グラフはエッジリストとして表現され、edges[i] = (u, v)はノードuからノードvへ向かう有向エッジを意味します。このとき、そこから出発すればグラフ内のすべてのノードに到達できるような、最小の頂点集合を見つける必要があります(頂点は任意の順序で返して構いません)。例えば、入力が次のような場合を考えてみましょう。この場合、出力は [0, 2, 3] となります。これらの頂点は他のどの頂点からも到達できないため、ここから探索を開始すれば全ノードをカバーできるから