Pythonでトラックに積載できる最大ユニット数を求めるプログラム(貪欲法による解法)
問題の概要
2次元配列 boxTypes が与えられます。各要素 boxTypes[i] は [i番目の種類の箱の個数, 1箱あたりのユニット数] の形式で表されます。さらに、トラックに積める箱の最大数を示す値 k も与えられます。
箱の総数が k を超えない範囲であれば、どの箱を選んでトラックに積んでも構いません。この条件のもとで、トラックに積載できるユニットの合計の最大値を求めましょう。
入力例
boxTypes = [[2,4],[3,3],[4,2]]、k = 6 の場合、出力は 19 になります。箱の内訳は以下の通りです。
- 種類1の箱:2個(それぞれ4ユニット入り)
- 種類2の箱:3個(それぞれ3ユニット入り)
- 種類3の箱:4個(それぞれ2ユニット入り)
k = 6 なので、種類1と種類2の箱をすべて積み、残りの枠1つ分には種類3の箱を1個だけ積めます。したがって、(2×4) + (3×3) + (1×2) = 8 + 9 + 2 = 19 ユニットが答えとなります。
解き方:貪欲法(グリーディ法)
この問題は「貪欲法」と呼ばれるアプローチで効率的に解けます。基本の考え方はシンプルで、1箱あたりのユニット数が多い箱から順に積んでいくというものです。手順は以下の通りです。
boxTypesを、1箱あたりのユニット数の降順でソートする- 変数
total := 0、fill := 0を初期化する boxTypesの各要素iに対して以下を繰り返すfill + i[0] <= kの場合:その種類の箱をすべて積み、fill += i[0]、total += i[0] * i[1]と更新する- それ以外の場合:残りの空きスペース分だけ積み、
total += (k - fill) * i[1]を加算してループを抜ける
totalを返す
Pythonでの実装例
実際のコードは以下のようになります。
def solve(boxTypes, k):
boxTypes.sort(key=lambda x: x[1], reverse=True)
total = 0
fill = 0
for i in boxTypes:
if fill + i[0] <= k:
fill += i[0]
total += i[0] * i[1]
else:
total += (k - fill) * i[1]
break
return total
boxTypes = [[2,4],[3,3],[4,2]]
k = 6
print(solve(boxTypes, k))入力
[[2,4],[3,3],[4,2]], 6
出力
19
計算量の目安
ソートに O(n log n)、その後の走査に O(n) を要するため、全体の時間計算量は O(n log n) です。ソートをインプレースで行えば、追加のメモリはほぼ不要で、空間計算量は O(1) に抑えられます。このように、単位あたりの価値が高いものから詰めていく貪欲戦略は、この種のナップサック型問題において最適解を保証できる代表的な手法です。
-
Pythonで株式の保有と売却により得られる最大利益を求めるプログラム
時系列順に並べられた企業の株価リスト nums が与えられたとします。1日につき最大1株まで購入でき、複数の銘柄を同時に保有することや、任意のタイミングで売却することが可能です。この条件のもとで、獲得できる利益の最大値を求めてください。たとえば、入力が nums = [3, 4, 7, 3, 5] の場合、出力は 9 になります。具体的には、価格が 3 と 4 のときにそれぞれ 1 株ずつ購入し、価格が 7 になった時点で両方とも売却します。その後、再び価格が 3 のときに購入し、価格が 5 のときに売却します。合計利益は (7 − 3) + (7 − 4) + (5 − 3) = 9 です。
-
Pythonで制約付きの建物の最大高さを求めるプログラム
問題の概要整数 n と制約リスト restrictions が与えられたとします。私たちは都市に n 棟の新しい建物を一列に建てようとしていますが、高さに関するいくつかの制限があります。建物には左から順に 1 から n までの番号が付けられており、各制約は restrictions[i] = (id_i, max_height_i) の形式で表され、「id_i 番の建物の高さは max_height_i 以下でなければならない」ことを意味します。建物の高さに関する都市の規則は以下のとおりです。各建物の高さは 0 以上でなければなりません。1 番の建物(最初の建物)の高さは必ず 0 です。隣接す