C++で解く三角形の最小パス和:動的計画法による効率的なアプローチ
問題概要
数値が三角形状に配置された構造が与えられます。頂点から最下段まで移動する際、各ステップで「下の行の隣接する数値」にのみ移動できるものとします。このとき、通過する数値の合計が最小となる経路の和を求めてください。
例
入力が以下の場合を考えます。
5 7 3 8 1 2 9 6 4 5
このとき最小の合計は 13 となり、その経路は次のとおりです。
5 + 3 + 1 + 4
アルゴリズム
- 動的計画法(DP)のメモ化テクニックを利用します。
- メモ化用として、1次元配列
memorizationを作成します。 - 各行
kに対して、以下の漸化式を適用します。
memorization[i] = min( memorization[i], memorization[i+1] ) + A[k][i];
この方法のポイントは、最下段から順に上へ向かって計算を進めることです。まず最下段の値をそのまま配列にコピーし、その後は下の行の隣接する2つの要素のうち小さい方を選びながら上へ更新していきます。こうすることで、最終的に memorization[0] に最小パス和が格納されます。また、2次元のDPテーブルを使わず1次元配列だけで処理できるため、空間計算量を O(n) に抑えられるのも大きな利点です。
C++実装例
#include <bits/stdc++.h>
using namespace std;
int getMinSum(vector<vector<int>> &arr) {
int memorization[arr.size()];
int n = arr.size() - 1;
for (int i = 0; i < arr[n].size(); ++i) {
memorization[i] = arr[n][i];
}
for (int i = arr.size() - 2; i >= 0; --i) {
for (int j = 0; j < arr[i + 1].size() - 1; ++j) {
memorization[j] = arr[i][j] +
min(memorization[j],
memorization[j + 1]);
}
}
return memorization[0];
}
int main() {
vector<vector<int>> arr = {
{5},
{7, 3},
{8, 1, 2},
{9, 6, 4, 5}};
cout << "Minimum sum path = " << getMinSum(arr) << endl;
return 0;
}
このプログラムをコンパイルして実行すると、以下の出力が得られます。
出力
Minimum sum path = 13
-
C++で解くパス合計III:DFSで二分木のルートからリーフまでの経路を探索
整数のキーを持つノードで構成される二分木が与えられたとき、合計値が指定した値と一致する「ルートからリーフ(葉)までの経路」をすべて見つける問題を考えます。経路は必ず根から始まり、葉で終わる必要があります。 問題の例 たとえば、次のような二分木 [5,4,8,11,null,13,4,7,2,null,null,5,1] があり、目標の合計値が 22 だとします。 このとき、条件を満たす経路は次の 2 本です。 [[5, 4, 11, 2], [5, 8, 4, 5]] 解法のアプローチ:DFS(深さ優先探索)+バックトラック この問題は、少し手を加えた DFS(深さ優先探索)関数で効率的に解
-
C++でNxNグリッドの最小下降パスの合計を求める方法
問題文N×Nのサイズを持つ整数行列 A が与えられます。この課題では、A を通る「下降パス(Falling Path)」の最小合計を求めることが目標です。下降パスは、最初の行の任意の要素から開始し、最後の行で終了します。パスは次の行ごとに1つの要素を選択していきます。ただし、次の行で選ぶ要素の列は、前の行で選んだ列と同じ列、または左右に1つだけ隣接する列でなければなりません。例N = 2、行列が以下の場合: { {5, 10}, {25, 15} } 出力は 20 となります(要素 5 と 15 が選択されるため)解法の考え方(動的計画法)この問題は動的計画法(DP)を用いるこ