最小限のコストでN本のロープを接続するアルゴリズム
長さの異なる N 本のロープが与えられます。これらをすべて連結しなければなりませんが、2 本のロープをつなぐコストは「その 2 本の長さの合計」となります。ここでの目的は、N 本すべてのロープを最小のコストで 1 本につなぎ合わせることです。
この問題はヒープ木(優先度付きキュー)を使うと効率よく解けます。まずすべてのロープの長さを最小ヒープに挿入し、ヒープから最も短いロープと 2 番目に短いロープを取り出して連結します。その後、連結後の長さを再びヒープに戻します。この操作を繰り返し、ヒープ内に要素が 1 つだけになった時点で処理を終了すれば、最小コストで連結されたロープが得られます。
この手法がうまく機能するのは、短いロープほど連結の対象になる回数が多いためです。毎回最も短い 2 本を選んでつなぐことで、短いロープがコスト計算に登場する回数を抑えられます。これは典型的な貪欲法(グリーディ法)の応用例といえます。
入力と出力
入力:
ロープの長さ:{4, 3, 2, 6, 5, 7, 12}
出力:
合計最小コスト:103
アルゴリズム
findMinCost(array, n)
入力 − ロープの長さのリスト、およびリスト内の要素数
出力 − ロープを連結する際の最小コスト
Begin
minCost := 0
配列の全要素で優先度付きキューを初期化(小さい値ほど高い優先度=最小ヒープ)
while キューのサイズが 1 より大きい間、繰り返す
item1 := キューから最小の要素を取り出して削除
item2 := キューから次に小さい要素を取り出して削除
minCost := minCost + item1 + item2
(item1 + item2) をキューに追加
done
return minCost
End
計算過程の例
入力 {4, 3, 2, 6, 5, 7, 12} の場合、処理は次のように進みます。
| 手順 | 連結する2本 | 連結コスト | 累計コスト |
|---|---|---|---|
| 1 | 2 + 3 | 5 | 5 |
| 2 | 4 + 5 | 9 | 14 |
| 3 | 5 + 6 | 11 | 25 |
| 4 | 7 + 9 | 16 | 41 |
| 5 | 11 + 12 | 23 | 64 |
| 6 | 16 + 23 | 39 | 103 |
最終的に、合計最小コストは 103 となります。
C++ による実装例
#include<iostream>
#include<queue>
#include<vector>
using namespace std;
int findMinimumCost(int arr[], int n) {
// 最小ヒープとして動作する優先度付きキューを用意
priority_queue< int, vector<int>, greater<int>> queue(arr, arr+n);
int minCost = 0;
while (queue.size() > 1) { // キューに2本以上のロープがある間
int item1 = queue.top(); // item1 は最も短いロープ
queue.pop();
int item2 = queue.top(); // item2 は2番目に短いロープ
queue.pop();
minCost += item1 + item2; // 連結コストを加算
queue.push(item1 + item2); // 連結したロープをキューに戻す
}
return minCost;
}
int main() {
int ropeLength[] = {4, 3, 2, 6, 5, 7, 12};
int n = 7;
cout << "Total minimum cost: " << findMinimumCost(ropeLength, n);
}
実行結果
Total minimum cost: 103
各ステップでヒープへの挿入と削除を行うため、このアルゴリズムの計算量は O(N log N) となります。ロープの本数が増えても効率的に動作するのが特徴です。
-
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で都市を最小コストで接続する方法|クラスカル法とUnion-Findによる実装
問題概要 1からNまでの番号が付けられたN個の都市があるとします。接続情報connectionsの各要素は[city1, city2, cost]という形式で与えられ、これはcity1とcity2を直接つなぐためのコストを表します。ここで求めたいのは、任意の2つの都市の間に必ず経路が存在する状態(全域木)を作るときの最小コストです。コストは採用した接続のコストの合計であり、すべての都市を接続できない場合は-1を返します。 たとえば、次のようなグラフが与えられたとします。 この場合の出力は6になります。3つの都市をすべてつなぐには2本の接続で十分なので、コストの小さい組み合わせ、すなわち[2