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

C++でNを1・3・4の和で表現する組み合わせの総数を求める方法(動的計画法)

正の整数 N が入力として与えられます。この記事では、N を「1」「3」「4」のみの合計として表現する方法が何通りあるかを求めるプログラムを紹介します。

例えば N = 4 の場合、「1+1+1+1」「3+1」「1+3」「4」の4通りの表し方があるため、答えは 4 となります。

具体例で理解しよう

例1

入力: N = 5

出力: N を 1、3、4 の和で表現する異なる方法の数:6

解説: 5 は以下のように表現できます。

  • 1+1+1+1+1
  • 1+3+1
  • 3+1+1
  • 1+1+3
  • 4+1
  • 1+4

例2

入力: N = 6

出力: N を 1、3、4 の和で表現する異なる方法の数:9

解説: 6 は以下のように表現できます。

  • 1+1+1+1+1+1
  • 3+1+1+1
  • 1+3+1+1
  • 1+1+3+1
  • 1+1+1+3
  • 3+3
  • 4+1+1
  • 1+4+1
  • 1+1+4

アルゴリズムの考え方

ここでは動的計画法(DP)を使って、N を 1、3、4 の和で表す方法の数を効率よく数えます。配列 arr[i] を用意し、i をそのような和で表現する方法の総数を arr[i] に格納していきます。

まず、ベースケースは次のようになります。

  • arr[0] = 1(何も選ばない1通りとみなす)
  • arr[1] = 1(「1」の1通り)
  • arr[2] = 1(「1+1」の1通り)
  • arr[3] = 2(「1+1+1」と「3」の2通り)

それ以降の数 i(4 以上)については、次の漸化式で求められます。

arr[i] = arr[i-1] + arr[i-3] + arr[i-4]

これは「最後に 1 を足した場合」「最後に 3 を足した場合」「最後に 4 を足した場合」の3つの場合に分解できるためです。

手順のまとめ

  • 正の整数 N を入力として受け取る。
  • 関数 Expres_sum(int N) が N を受け取り、1・3・4 の和で表現する方法の数を返す。
  • 結果を保存するための配列 arr[N+1] を用意する。
  • ベースケースとして arr[0] = 1、arr[1] = 1、arr[2] = 1、arr[3] = 2 を初期化する。
  • i = 4 から i <= N までループ処理を行う。
  • 各 i について arr[i] = arr[i-1] + arr[i-3] + arr[i-4] を計算する。
  • ループ終了後、arr[N] を結果として返す。

実装例

#include <bits/stdc++.h>
using namespace std;
int Expres_sum(int N) {
    int arr[N + 1];
    arr[0] = 1;
    arr[1] = 1;
    arr[2] = 1;
    arr[3] = 2;
    for (int i = 4; i <= N; i++) {
        arr[i] = arr[i - 1] + arr[i - 3] + arr[i - 4];
    }
    return arr[N];
}
int main() {
    int N = 5;
    cout << "Count of different ways to express N as the sum of 1, 3 and 4 are: " << Expres_sum(N);
    return 0;
}

上記のコードを実行すると、次のような出力が得られます。

出力

Count of different ways to express N as the sum of 1, 3 and 4 are: 6

計算量について

この動的計画法によるアプローチでは、各 i の値を一度ずつ計算するだけなので、時間計算量は O(N)、配列を使用するため空間計算量も O(N) となります。全ての組み合わせを列挙する指数時間の探索に比べ、非常に効率的に答えを求められるのがポイントです。

  1. C++でXとの合計がフィボナッチ数になるノードを数える方法

    各ノードに数値の重みが割り当てられた二分木が与えられます。この記事の目的は、「ノードの重み + X」の計算結果がフィボナッチ数となるノードの個数を求めることです。フィボナッチ数列とは、0, 1, 1, 2, 3, 5, 8, 13… のように続く数列で、n番目の数は(n−1)番目と(n−2)番目の数の和になります。たとえば重みが13であればフィボナッチ数に該当するため、そのノードはカウント対象となります。入力例1temp = 1 の場合。値を入力すると、以下のような木が構成されます。出力Count the nodes whose sum with X is a Fibonacci number

  2. C++で1×mサイズのタイルを使ってn×mの床を敷き詰める方法の数を数える

    問題概要部屋の床の長さと幅を表す 2 つの整数 n と m が与えられます。この床をサイズ 1×m のタイルで敷き詰める方法が何通りあるかを数えることが目的です。入力例 1n=3 m=2出力例 11 x m サイズのタイルを使用して n x m の床を敷き詰める方法の数は:3説明下図のように、1×2 のタイル 3 枚を並べる方法が 3 通り存在します。入力例 2n=3 m=3出力例 21 x m サイズのタイルを使用して n x m の床を敷き詰める方法の数は:2説明1×3 のタイル 3 枚をすべて縦方向に並べる方法と、すべて横方向に並べる方法があり、合計 2 通りとなります。考え方(アプロー