手持ちのコインでnルピーを作る組み合わせの数を求めるPythonプログラム
1ルピー、2ルピー、5ルピー、10ルピーという4種類の額面のコインが与えられているとします。このとき、これらのコインを使って合計 n ルピーを作る方法が何通りあるかを求めるのが本記事の目的です。
コインの所持枚数は、4つの要素を持つ配列 count で表されます。count[0] は1ルピーコインの枚数、count[1] は2ルピーコインの枚数、以降も同様に対応します。
たとえば、入力が n = 27、count = [8, 4, 3, 2] の場合、出力は 18 となります。つまり18通りの組み合わせが存在し、その一部は次のとおりです。
- 10×2 + 5×1 + 2×1 = 27
- 10×2 + 2×3 + 1×1 = 27
- 10×1 + 5×3 + 2×1 = 27
- 10×1 + 5×1 + 2×4 + 1×4 = 27
など、他にも多数の組み合わせがあります。
解き方のアプローチ
この問題は動的計画法(DP)を用いて効率的に解くことができます。手順は以下のとおりです。
- 額面のリストを用意する:
denom = [1, 2, 5, 10] - サイズ
n + 1の配列Aを作り、すべて0で初期化する Aをコピーした作業用リストBを用意するiを 0 からmin(count[0], n)まで繰り返し、A[i] = 1とする(1ルピーコインだけで作れる金額の初期化)iを 1 から 3 まで繰り返し、各額面について以下を処理する:jを 0 からcount[i]まで繰り返し、さらにkを 0 からn + 1 - j * denom[i]まで繰り返して、B[k + j * denom[i]] += A[k]を行う
- 処理後、
jを 0 からnまで繰り返し、A[j] = B[j]として結果を反映し、B[j] = 0でリセットする - 最後に
A[n]を返す
実装例
理解を深めるために、実際のPythonコードを見てみましょう。
denom = [1,2,5,10]
def solve(n, count):
A = [0 for _ in range(n+1)]
B = list(A)
for i in range(min(count[0], n) + 1):
A[i] = 1
for i in range(1, 4):
for j in range(0, count[i] + 1):
for k in range(n + 1 - j * denom[i]):
B[k + j * denom[i]] += A[k]
for j in range(0, n + 1):
A[j] = B[j]
B[j] = 0
return A[n]
n = 27
count = [8,4,3,2]
print(solve(n, count))入力
27, [8,4,3,2]
出力
18
まとめ
このプログラムでは、まず1ルピーコインだけで作れる金額のパターンを初期化し、その後2ルピー、5ルピー、10ルピーのコインを順に加えながら、各金額に対する組み合わせの数を累積的に更新していきます。コインの枚数に上限がある制約付きの組み合わせ問題に対して、動的計画法が有効であることを示す良い例といえます。
-
Pythonで条件に基づいてリスト内のすべての組み合わせを抽出する方法
ネストされたリスト構造から、指定した条件に従ってすべての組み合わせを取り出したい場面はよくあります。Pythonでは、シンプルな反復処理(whileループとforループ)、appendメソッド、そしてisinstance関数を組み合わせることで、この処理を簡単に実現できます。 実装例 以下のコードは、文字列とリストが混在するリストから、各サブリストの同じインデックス位置にある要素を組み合わせて、新しいリストを生成する例です。 my_list = [python, [15, 12, 33, 14], is, [fun, easy, better, cool]] print(The list i
-
Pythonで指定されたインデックスに基づいて文字列をシャッフルする方法
文字列 s とインデックスのリスト ind が与えられ、両者は同じ長さであるとします。文字列 s は、位置 i にある文字が最終的な文字列内の ind[i] の位置へ移動するようにシャッフルされます。このとき、シャッフル後の最終的な文字列を求める必要があります。例えば、入力が s = ktoalak、ind = [0,5,1,6,2,4,3] の場合、出力は kolkata となります。解決手順この問題を解くには、以下の手順に従います。fin_str を s と同じサイズのリストとして作成し、0で初期化するs 内の各インデックス i と各文字 v に対して、次の操作を行うfin_str[ind