C#
 Computer >> コンピューター >  >> プログラミング >> C#

C#のボトムアップ方式で「1にする最小ステップ数」を実装する方法

問題の概要:「1にする最小ステップ数」とは

「1への最小ステップ数(Minimum Steps to One)」は、動的計画法(DP)の入門問題としてよく知られています。整数 n が与えられ、次の3種類の操作を繰り返し適用して、n を 1 に到達させるまでの最小回数を求めます。

  • 操作1: n が 3 で割り切れるとき、n を 3 で割る
  • 操作2: n が 2 で割り切れるとき、n を 2 で割る
  • 操作3: 常に実行可能。n から 1 を引く

ボトムアップ方式(Tabulation)の考え方

ボトムアップ方式では、再帰呼び出しを行わずに、小さな部分問題から順番に答えを計算し、dp 配列に結果を保存していきます。dp[i] は「i を 1 にするために必要な最小ステップ数」を表します。

アルゴリズムの手順

  1. 整数 n を入力として受け取ります。
  2. 初期条件として、n が 1 の場合は 0 を返します。
  3. 候補値 op1・op2・op3 を最大値(int.MaxValue)で初期化します。
  4. i が 3 で割り切れる場合は、op1 に dp[i / 3] を代入します。
  5. i が 2 で割り切れる場合は、op2 に dp[i / 2] を代入します。
  6. op3 には常に dp[i - 1] を代入します。
  7. dp[i] = min(op1, op2, op3) + 1 として最小ステップ数を記録します。
  8. すべての計算が終わったら、dp 配列から最終的な値を返します。

C#での実装例

public class DynamicProgramming{
    public int MinimumStepstoOne(int n){
        int[] dp = new int[100];
        dp[1] = 0;
        for (int i = 2; i <= n; i++){
            int op1 = int.MaxValue, op2 = int.MaxValue, op3 = int.MaxValue;
            if (i % 3 == 0){
                op1 = dp[i / 3];
            }
            if (i % 2 == 0){
                op2 = dp[i / 2];
            }
            op3 = dp[i - 1];
            dp[i] = Math.Min(Math.Min(op1, op2), op3) + 1;
        }
        return dp[n];
    }
}

static void Main(string[] args){
    DynamicProgramming dp = new DynamicProgramming();
    Console.WriteLine(dp.MinimumStepstoOne(10));
}

実行結果

3

なぜ「n = 10 で 3 ステップ」になるのか

n = 10 の場合、最短経路は次のようになります。

10 → 9(−1)→ 3(÷3)→ 1(÷3)

このように、単純に 1 を引き続けるだけでは 4 ステップ以上かかるところを、割り算をうまく組み合わせることで 3 ステップに短縮できます。これこそが動的計画法による最適化のポイントです。

計算量

時間計算量: O(N) ― 各 i に対して定数回の比較と配列参照しか行わないためです。

空間計算量: O(N) ― 中間結果を保存するための dp 配列が必要になるためです。

  1. Java 9でJavaFXを使ってJShellをプログラムから実装する方法

    JShellは、サンプル式を対話的に実行できるツールです。通常はコマンドラインから利用しますが、JavaFXアプリケーションの中でプログラム的にJShellを実装することも可能です。その場合、Javaプログラムに以下のパッケージをインポートする必要があります。import jdk.jshell.JShell; import jdk.jshell.SnippetEvent; import jdk.jshell.VarSnippet;これらのクラスの役割は次のとおりです。JShell:評価エンジンの本体。式や文を評価(eval)するためのAPIを提供します。SnippetEvent:評価結果として

  2. Javaでスタックを使ってキュー(Queue)を実装する方法を解説

    キューとスタックの基本Queue(キュー)は Collection インターフェースを継承したクラスで、FIFO(First-In-First-Out:先入れ先出し)方式による要素の挿入と削除をサポートします。一方、Stack(スタック)は Vector クラスのサブクラスであり、LIFO(Last-In-First-Out:後入れ先出し)方式でオブジェクトを管理します。つまり、スタックの一番上に追加された最後の要素が、最初に取り出される要素になります。この2つのデータ構造の性質は正反対ですが、スタックを2つ組み合わせることで、キューを実装することが可能です。以下では、その具体的な実装方法を紹