C#でボトムアップアプローチを使ってコイン両替問題を実装する方法
コイン両替問題とは
コイン両替問題は、指定された金額を、使用できるコインの種類だけで「最小枚数」で支払う方法を求める、動的計画法の代表的な応用例です。貪欲法(常に一番額面の大きいコインから選ぶ方法)では最適解が得られないコイン体系(例:{1, 7, 10})でも、動的計画法を使えば確実に最小枚数を求められます。
ボトムアップアプローチの考え方
ボトムアップアプローチ(タブレーション)では、金額0のような小さな部分問題から順に解き、その結果を配列に記録しながら目的の金額へと積み上げていきます。トップダウン方式(メモ化再帰)と違い、再帰呼び出しが不要なためスタックオーバーフローを気にせずに済むのが大きな利点です。
CoinChangeBottomUpApproach メソッドは、次の3つのパラメータを受け取ります。
- n: 支払うべき金額
- coins: 使用可能なコインの額面を格納した配列
- t: コインの種類数(配列の要素数)
処理の流れは以下のとおりです。
- これまでに計算した値を保持するためのDP配列(dp)を宣言します。dp[i] には「金額iを支払うのに必要な最小コイン枚数」が格納されます。
- 金額1からnまで順番にループし、各金額についてすべてのコインを試しながら最小枚数を計算します。
- 「現在の金額 − コインの額面」という部分問題の解がすでにdp配列に保存されていれば、それを再利用して重複計算を回避します。
- 最終的に dp[n] の値が答えとなります。
計算量
- 時間計算量: O(N)(厳密にはコインの種類数Tを掛けた O(N×T)。Tを定数とみなせば O(N))
- 空間計算量: O(N)(DP配列の分だけメモリを使用)
実装例(C#)
using System;
public class DynamicProgramming {
// dp[i] = 金額iを支払うのに必要な最小コイン枚数
public int CoinChangeBottomUpApproach(int n, int[] coins, int t) {
int[] dp = new int[n + 1];
for (int i = 1; i <= n; i++) {
dp[i] = int.MaxValue;
for (int j = 0; j < t; j++) {
// コインcoins[j]が使用可能で、残り金額の解が計算済みの場合
if (i - coins[j] >= 0 && dp[i - coins[j]] != int.MaxValue) {
int subProb = dp[i - coins[j]];
dp[i] = Math.Min(dp[i], subProb + 1);
}
}
}
return dp[n];
}
}
public class Program {
static void Main(string[] args) {
DynamicProgramming dp = new DynamicProgramming();
int[] coins = { 1, 7, 10 };
int ss = dp.CoinChangeBottomUpApproach(15, coins, coins.Length);
Console.WriteLine(ss);
}
}
出力結果
3
実行結果の解説
この例では、金額15をコイン {1, 7, 10} で支払うケースを扱っています。最適な組み合わせは「7 + 7 + 1」の3枚であり、プログラムも正しく3を出力します。
もし貪欲法で「10 + 1×5」と選んでしまうと6枚必要となり、最適解になりません。この比較からも、動的計画法によって全パターンを網羅的に評価することの有効性がわかります。
まとめ
ボトムアップアプローチでは、小さな金額から順に最小コイン枚数を表に埋めていくことで、重複計算を排除し、効率的に答えを求められます。コイン両替問題は動的計画法の入門に最適な題材なので、ぜひ別のコイン体系や金額でも試してみてください。
-
C++とOpenCVで画像のコントラストを変更する方法を解説
画像処理において、明るさやコントラストの調整は最もよく使われる編集効果のひとつです。本記事では、OpenCVを使って画像のコントラストを変更する方法を学びます。 コントラストとは何か コントラストは、画像のシャープさ(鮮明さ)を左右する重要な要素です。コントラストが高いほど画像はくっきりとシャープに見え、逆にコントラストが低いほど、柔らかく滑らかな印象になります。 コントラストを変更するということは、ピクセル値の重みを増減させることを意味します。具体的には、各ピクセルの値にある定数を掛けることで実現できます。例えば、画像内のすべてのピクセル値に「2」を掛けると、ピクセル値が2倍になり、結果とし
-
Java 9でJavaFXを使ってJShellをプログラムから実装する方法
JShellは、サンプル式を対話的に実行できるツールです。通常はコマンドラインから利用しますが、JavaFXアプリケーションの中でプログラム的にJShellを実装することも可能です。その場合、Javaプログラムに以下のパッケージをインポートする必要があります。import jdk.jshell.JShell; import jdk.jshell.SnippetEvent; import jdk.jshell.VarSnippet;これらのクラスの役割は次のとおりです。JShell:評価エンジンの本体。式や文を評価(eval)するためのAPIを提供します。SnippetEvent:評価結果として