【C++】0行目の任意のセルから始まり、(N-1)行目の任意のセルで終わる最大パス合計の求め方
本記事では、行列の0行目(最上行)の任意のセルから出発し、(N-1)行目(最下行)の任意のセルで終了する経路の中で、通過したセルの値の合計が最大になる「最大パス合計」を求めるプログラムについて解説します。
問題の概要
N×N の行列が与えられます。現在いるセル (i, j) からは、次の3種類の移動のみが許可されています。
(i+1, j)… 真下へ移動(i+1, j-1)… 左下へ移動(i+1, j+1)… 右下へ移動
つまり、必ず1行ずつ下へ進みながら、左右に最大1列だけずれて移動できるという制約があります。この条件のもとで、出発点と到達点を自由に選び、経路上のセルの値の総和を最大化することが目的です。
解法のアプローチ(動的計画法)
この問題は動的計画法(DP)を用いることで効率的に解けます。考え方は次のとおりです。
- dp テーブルを用意し、0行目の各セルの値をそのまま初期値として設定します。
- i 行目のセル
(i, j)に到達できるのは、直前の行の(i-1, j-1)、(i-1, j)、(i-1, j+1)の3セルです。これらの dp 値の最大値に現在のセルの値を加えたものがdp[i][j]となります。 - すべての行の計算が終わったら、最終行((N-1)行目)の dp 値の最大値が答えとなります。
計算量は時間・空間ともに O(N²) であり、全経路を網羅的に探索するよりはるかに効率的です。
実装例
#include<bits/stdc++.h>
using namespace std;
#define N 4
// 最大パス合計を求める関数
int MaximumPath(int Mat[][N]) {
int result = 0 ;
int dp[N][N+2];
memset(dp, 0, sizeof(dp));
// 0行目の値をそのまま初期化
for (int i = 0 ; i < N ; i++)
dp[0][i+1] = Mat[0][i];
// 上の行の3方向から最大値を選んで累積
for (int i = 1 ; i < N ; i++)
for (int j = 1 ; j <= N ; j++)
dp[i][j] = max(dp[i-1][j-1], max(dp[i-1][j], dp[i-1][j+1])) + Mat[i][j-1] ;
// 最終行の最大値が答え
for (int i=0; i<=N; i++)
result = max(result, dp[N-1][i]);
return result ;
}
int main() {
int Mat[4][4] = {
{ 4, 2 , 3 , 4 },
{ 2 , 9 , 1 , 10},
{ 15, 1 , 3 , 0 },
{ 16 ,92, 41, 44 }
};
cout << MaximumPath ( Mat ) <<endl ;
return 0;
}
出力結果
120
この例では、例えば「4 → 10 → 15 → 92」といった経路ではなく、DPによって選ばれた最適な経路をたどることで合計値 120 が得られます。dp テーブルには各行の時点での「そこまでの最大合計」が記録されていくため、最終行を見るだけで全体の最大値が分かる仕組みになっています。
-
C++を使って行列内で合計が最大の列を見つける方法
ここでは、サイズ M × N の行列が与えられたときに、要素の合計が最大となる列を見つける方法を解説します。この問題では、難しいアルゴリズムを用いる必要はありません。行列を列方向に走査して各列の合計値を計算し、その合計が最大であれば、合計値と該当する列のインデックスを出力するというシンプルなアプローチで十分です。アルゴリズムの手順処理の流れは以下の通りです。1. 最大合計値を格納する変数 maxSum を INT_MIN で初期化し、列のインデックスを格納する index を -1 に設定します。2. 各列(0 ~ N-1)について、colSum 関数を使ってその列の要素の合計を計算します。3
-
【C++】分割統治法で最大部分配列和を求める方法を解説
正の値と負の値が混在する数列が与えられたとき、その中から「要素が連続する部分配列(サブアレイ)」のうち合計が最大になるものを求める問題を考えます。例えば、数列 {-2, -5, 6, -2, -3, 1, 5, -6} の場合、最大部分配列和は 7 となり、これは {6, -2, -3, 1, 5} の合計に相当します。この問題は、分割統治法(Divide and Conquer)を用いることで効率的に解くことができます。アルゴリズムの手順配列を中央で2つに分割する以下の3つの値のうち最大のものを求める左側の部分配列における最大部分配列和右側の部分配列における最大部分配列和中央をまたいで(左右