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

C++で解く!行列の上から下への最大合計パスを求めるアルゴリズム

問題概要

n×n の行列を考えます。行列の各セル(マス)には何らかの値が割り当てられています。移動は、i 行目のセルから (i+1) 行目の斜め下のセルにのみ行うことができます。つまり、セル (i, j) から移動できるのは、セル (i+1, j-1) とセル (i+1, j+1) の2か所だけです。この条件に従って最上行から最下行まで移動する経路の中で、通過するセルの値の合計が最大となる経路を求めてください。

入力例

{
    {5, 6, 1, 17},
    {-2, 10, 8, -1},
    { 3, -7, -9, 4},
    {12, -4, 2, 2}
}

この場合、最大合計は (17 + 8 + 4 + 2) = 31 となります。

アルゴリズムの考え方

  • 最上行の各セルを起点として、そこから最下行まで辿れるすべての経路の最大合計を求め、最終的にその中で最大の値を返します。
  • 同じ部分問題の結果が何度も必要になるため、動的計画法(Dynamic Programming)を活用します。

具体的には、dp[i][j] を「セル (i, j) から最下行まで移動するときに得られる合計の最大値」と定義します。最下行では dp[n-1][j] = mat[n-1][j] であり、それより上の行では次の漸化式が成り立ちます。

dp[i][j] = mat[i][j] + max(dp[i+1][j-1], dp[i+1][j+1])

この計算を下の行から順番に行っていき、最後に最上行 dp[0][j] の最大値を答えとします。計算量は O(n²) であり、すべての経路を素朴に探索する指数時間のアプローチと比べてはるかに効率的です。

C++による実装例

#include <bits/stdc++.h>
using namespace std;
#define SIZE 10
int getMaxMatrixSum(int mat[SIZE][SIZE], int n){
    if (n == 1) {
       return mat[0][0];
    }
    int dp[n][n];
    int maxSum = INT_MIN, max;
    for (int j = 0; j < n; j++) {
       dp[n - 1][j] = mat[n - 1][j];
    }
    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;
       }
    }
    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, 17},
        {-2, 10, 8, -1},
        {3, -7, -9, 4},
        {12, -4, 2, 2}
    };
    int n = 4;
    cout << "Maximum Sum = " << getMaxMatrixSum(mat, n) << endl;
    return 0;
}

実行結果

上記のプログラムをコンパイルして実行すると、以下の出力が得られます。

Maximum Sum = 31
  1. C++で二分木における2つの葉ノード間の最大パス合計を求める方法

    問題の概要 この問題では、各ノードが値を持つ二分木が与えられます。私たちのタスクは、二分木における2つの葉ノード(リーフノード)間の最大パス合計を求めるプログラムを作成することです。 ここで求めるのは、値の合計が最大になるような、ある葉ノードから別の葉ノードへのパスです。この最大合計パスには、ルートノードが含まれる場合もあれば、含まれない場合もあります。 二分木(Binary Tree)とは、各ノードが最大2つの子ノードを持つことができる木構造のデータ構造です。それぞれの子ノードは「左の子(left child)」と「右の子(right child)」と呼ばれます。 具体例 以下のような二分木

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

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