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

【C++】動的計画法で行列の上から下への最大合計パスを求める方法

このチュートリアルでは、C++を使って、N×Nの行列(マトリックス)の最上行から最下行までの「最大合計パス」を求める方法を解説します。

問題の概要

N×Nサイズの整数行列が与えられます。最上行のいずれかのセルから出発し、1行ずつ下へ進みながら最下行に到達するまでの経路のうち、通過したセルの値の合計が最大になるものを見つけるのが目的です。移動先として選べるのは、次の行の斜め下(左下または右下)のセルのみです。

アプローチ:動的計画法(DP)

すべての経路を総当たりで調べると計算量が爆発的に増えてしまいますが、動的計画法を使えばO(N²)の計算量で効率的に解くことができます。手順は以下の通りです。

  1. 初期化:最下行の各セルはそれ以上下に進めないため、そのセルの値がそのままDPテーブルの値になります。
  2. 遷移:下から2番目の行から順に上へ向かって計算します。セル(i, j)のDP値は「自分の値 mat[i][j] + 次の行にある左斜め下 (i+1, j-1) と右斜め下 (i+1, j+1) のDP値のうち大きい方」となります。
  3. 答え:すべての行の計算が完了したら、最上行のDP値の中で最大のものが求める答えになります。

計算量は時間・空間ともにO(N²)です。

サンプルコード

#include <bits/stdc++.h>
using namespace std;
#define SIZE 10

// 最大合計パスを求める関数
int maxSum(int mat[SIZE][SIZE], int n) {
    if (n == 1)
        return mat[0][0];
    int dp[n][n];
    int maxSum = INT_MIN, max;
    // 最下行の値をそのままDPテーブルに設定
    for (int j = 0; j < n; j++)
        dp[n - 1][j] = mat[n - 1][j];
    // 下の行から順にDPテーブルを更新
    for (int i = n - 2; i >= 0; i--) {
        for (int j = 0; j < n; j++) {
            max = INT_MIN;
            // 左斜め下のセルと比較
            if (((j - 1) >= 0) && (max < dp[i + 1][j - 1])) max = dp[i + 1][j - 1];
            // 右斜め下のセルと比較
            if (((j + 1) < n) && (max < dp[i + 1][j + 1])) max = dp[i + 1][j + 1];
            dp[i][j] = mat[i][j] + max;
        }
    }
    // 最上行のDP値の最大値を返す
    for (int j = 0; j < n; j++)
        if (maxSum < dp[0][j])
            maxSum = dp[0][j];
    return maxSum;
}

int main() {
    int mat[SIZE][SIZE] = {
        { 5, 6, 1, 7 },
        { -2, 10, 8, -1 },
        { 3, -7, -9, 11 },
        { 12, -4, 2, 6 }
    };
    int n = 4;
    cout << "Maximum Sum = " << maxSum(mat, n);
    return 0;
}

実行結果

Maximum Sum = 28

結果の解説

この例の場合、右上端の「7」からスタートし、「8」「11」「2」とジグザグに斜め下へ進む経路(7 → 8 → 11 → 2)を選ぶと合計が28となり、これが最大値になります。負の値を含む行列でも、DPテーブルによって各セルからの最適な選択が保証されるため、正しく最大合計を求められる点がこの手法の強みです。

  1. C++で三角形の最大パス合計を求める方法

    この問題では、三角形の形に配置された数値が与えられます。私たちのタスクは、三角形の中で最大のパス合計を見つけるプログラムを作成することです。要素は、1行目に1つの要素から始まり、行が進むごとに要素数が1つずつ増えていき、n行目まで配置されます。つまり、プログラムは三角形内の要素の合計が最大となるパスを見つける必要があります。頂点から下へ進む際に、隣接する行の要素を選びながら、合計が最大になる経路を求めるのが目標です。具体例を使って問題を理解しましょう。入力例と出力例入力 −   1  5 6 8 2 9出力 − 16説明 −頂点から下

  2. C++を使って行列内で合計が最大の列を見つける方法

    ここでは、サイズ M × N の行列が与えられたときに、要素の合計が最大となる列を見つける方法を解説します。この問題では、難しいアルゴリズムを用いる必要はありません。行列を列方向に走査して各列の合計値を計算し、その合計が最大であれば、合計値と該当する列のインデックスを出力するというシンプルなアプローチで十分です。アルゴリズムの手順処理の流れは以下の通りです。1. 最大合計値を格納する変数 maxSum を INT_MIN で初期化し、列のインデックスを格納する index を -1 に設定します。2. 各列(0 ~ N-1)について、colSum 関数を使ってその列の要素の合計を計算します。3