C++で解く「金鉱で採れる最大のゴールド量を求めるパス」問題
サイズ m × n の金鉱グリッドが与えられます。各マスにはそのマスに含まれるゴールドの量を表す整数が書かれており、0 は空のマスを意味します。以下の条件のもとで、収集できるゴールドの最大量を求めるのがこの問題の目的です。
問題の条件
- マスに到達するたびに、そこにあるすべてのゴールドを回収します。
- 現在位置からは、上下左右のいずれかに1歩移動できます。
- 同じマスは一度しか訪問できません。
- ゴールドが 0 のマスは絶対に訪れてはいけません。
たとえば、入力が [[0,6,0],[5,8,7],[0,9,0]] の場合、答えは 24 になります。これは「9 → 8 → 7」という経路をたどることで最大のゴールドを得られるためです。
アプローチ:DFS(深さ優先探索)による全経路の探索
この問題は、各マスを起点として DFS を実行し、取りうるすべての経路の中から最大値を求めることで解けます。具体的な手順は次のとおりです。
DFS 関数の設計
dfs(grid, n, m, i, j)というメソッドを作成します。- 座標
(i, j)がグリッド外に出た場合、またはgrid[i][j]が -1(訪問済み)や 0(空)の場合は 0 を返します。 temp := grid[i][j]として現在の値を退避し、cost := grid[i][j]を初期化した上で、grid[i][j] = -1として訪問済みマークを付けます。costに、4方向(上・下・左・右)への再帰呼び出し結果の最大値を加算します。- 処理が終わったら
grid[i][j] = tempで元の値に戻し(バックトラック)、costを返します。
メイン関数の流れ
- 行数
n、列数mを取得し、答えans = 0で初期化します。 - すべてのマス
(i, j)についてループし、値が 0 以外のマスからdfsを開始して、ansを最大値で更新していきます。 - 最後に
ansを返します。
C++ 実装例
#include <bits/stdc++.h>
using namespace std;
class Solution {
public:
int dfs(vector<vector<int>>& grid, int n, int m, int i, int j){
if(i>=n || j>=m ||i<0||j<0 || grid[i][j]==-1 || grid[i][j] == 0)return 0;
int temp =grid[i][j];
int cost = grid[i][j];
grid[i][j] = -1;
cost+=max({dfs(grid,n,m,i+1,j),dfs(grid,n,m,i-1,j),dfs(grid,n,m,i,j+1),dfs(grid,n,m,i,j-1)});
grid[i][j] = temp;
return cost;
}
int getMaximumGold(vector<vector<int>>& grid) {
int n = grid.size() ;
int m = grid[0].size();
int ans = 0;
for(int i =0;i<n;i++){
for(int j =0;j<m;j++){
if(grid[i][j]){
ans = max(ans,dfs(grid,n,m,i,j));
}
}
}
return ans;
}
};
main(){
vector<vector<int>> v = {{0,6,0},{5,8,7},{0,9,0}};
Solution ob;
cout << (ob.getMaximumGold(v));
}
入力例
[[0,6,0],[5,8,7],[0,9,0]]
出力例
24
計算量について
この手法では、各マスを起点に4方向への探索を繰り返すため、最悪計算量は O((m×n) × 4^(m×n)) となります。ただし、実際にはゴールドが 0 のマスや訪問済みマスを枝刈りすることで、多くの場合これより大幅に小さい探索範囲で済みます。バックトラックによってグリッドの状態を毎回復元している点が、この実装の重要なポイントです。
-
【C++】バックトラッキングでグリッドの8つのマスに1〜8の数字を条件付きで配置する方法
この記事では、図の中にある8つの丸(マス)に「1」から「8」までの数字を、「数列上で隣り合う数字同士がグリッド上でも隣接しない」という条件を満たすように配置する問題を、C++で解く方法を解説します。問題の概要たとえば、入力として次のような3×4のグリッドが与えられたとします。「0」は使用しないマス、「-1」はまだ数字が置かれていない空きマスを表します。0-1-10-1-1-1-10-1-10この場合の出力は次のようになります。 3 5 7 1 8 2 4 6この結果では、たとえば「1」と「2」、「7」と「8」のように数列で連続する数字が、グリッド上で上下左右・斜めに隣り合わないように配置
-
C++で二分木における2つの葉ノード間の最大パス合計を求める方法
問題の概要 この問題では、各ノードが値を持つ二分木が与えられます。私たちのタスクは、二分木における2つの葉ノード(リーフノード)間の最大パス合計を求めるプログラムを作成することです。 ここで求めるのは、値の合計が最大になるような、ある葉ノードから別の葉ノードへのパスです。この最大合計パスには、ルートノードが含まれる場合もあれば、含まれない場合もあります。 二分木(Binary Tree)とは、各ノードが最大2つの子ノードを持つことができる木構造のデータ構造です。それぞれの子ノードは「左の子(left child)」と「右の子(right child)」と呼ばれます。 具体例 以下のような二分木