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

Pythonで2次元行列から収集できるコインの最大量を求めるプログラム

問題の概要

ここでは、2次元の行列(マトリックス)を扱います。各セル mat[r][c] には、そのマスに置かれたコインの枚数が格納されています。プレイヤーは任意のマスからスタートし、「上・下・左・右」の4方向(斜め移動は不可)に移動しながらコインを集めていきます。

移動したマスのコインはすべて回収され、そのマスの値は 0 に変わります。さらに、コインが 0 枚のマスには立ち入ることができないという制約があります。この条件下で、収集できるコインの合計の最大値を求めるのが本記事の目的です。

これは典型的なグラフ探索の問題であり、一度訪れたマスは二度と使えないため、「重み付きグリッド上の最長経路問題」として捉えることができます。解法としては、深さ優先探索(DFS)バックトラッキング を組み合わせるのが有効です。

入力例と出力

例として、次のような行列を考えてみましょう。

243
360
2012

この場合、出力は 18 になります。2 → 3 → 6 → 4 → 3 という経路をたどることで、コインを合計18枚収集できるためです。なお、右下の 12 は周囲が 0 のマスに囲まれているため、そもそも到達できません。

アルゴリズムの手順

この問題を解くために、以下の手順に従います。

  • 行列が空の場合は 0 を返します。
  • 行数を n、列数を m とします。
  • 移動方向を表すオフセット x = [-1, 1, 0, 0]y = [0, 0, -1, 1] を用意します(それぞれ上下左右に対応)。
  • 再帰関数 util(a, b) を定義します。この関数は、マス (a, b) から探索を始めたときに収集できるコインの最大値を返します。
    • ret = 0 で初期化します。
    • 4方向それぞれについて、移動先 (t1, t2) が有効なマス(範囲内かつコインが残っている)であれば:
      • そのマスのコイン数 t を退避させ、mat[t1][t2] = 0 として訪問済みマークを付けます。
      • ret = max(ret, util(t1, t2) + t) で最大値を更新します。
      • 探索が終わったら mat[t1][t2] = t と元に戻します(バックトラッキング)。
    • 最終的な ret を返します。
  • メイン処理では、すべてのマスを走査し、コインが存在するマスを起点として util() を呼び出します。起点のマス自体も一時的に 0 にしてから呼び出し、得られた結果の最大値を res に記録して返します。

Pythonでの実装例

class Solution:
   def solve(self, mat):
      if not mat:
         return 0
      n, m = len(mat), len(mat[0])
      x, y = [-1, 1, 0, 0], [0, 0, -1, 1]

      def ok(a, b):
         # 範囲内かつコインが残っているマスかどうかを判定
         return 0 <= a < n and 0 <= b < m and mat[a][b]

      def util(a, b):
         ret = 0
         for k in range(4):
            t1, t2 = x[k] + a, y[k] + b
            if ok(t1, t2):
               t, mat[t1][t2] = mat[t1][t2], 0  # 訪問済みにする
               ret = max(ret, util(t1, t2) + t)
               mat[t1][t2] = t  # バックトラック(状態を元に戻す)
         return ret

      res = 0
      for i in range(n):
         for j in range(m):
            if mat[i][j]:
               temp, mat[i][j] = mat[i][j], 0  # 起点も訪問済みにする
               res = max(res, util(i, j) + temp)
      return res

ob = Solution()
matrix = [
   [2, 4, 3],
   [3, 6, 0],
   [2, 0, 12]
]
print(ob.solve(matrix))

入力

[
   [2, 4, 3],
   [3, 6, 0],
   [2, 0, 12]
]

出力

18

計算量に関する注意点

各マスから最大4方向へ分岐する再帰探索を行うため、最悪の場合、計算量はマスの総数に対して指数的に増大します(O(4n×m) オーダー)。そのため、このアプローチは小〜中規模のグリッドに適しています。より大きな入力を扱う場合は、訪問済みマスの集合をビット列で管理するビットDP(動的計画法)などによる高速化を検討するとよいでしょう。

  1. Pythonでグリッド上に集められるコインの最大数を求めるプログラム

    問題の概要各セルにコインが置かれた2次元行列(マトリックス)があるとします。左上の [0,0] の位置からスタートし、右または下にのみ移動できるという制約のもとで、右下隅まで移動する過程で収集できるコインの最大数を求めるのがこの問題です。例として、次のような入力が与えられた場合を考えてみましょう。14226005この場合、出力は 14 になります。これは、パス [1, 4, 2, 2, 5] を通ることで、合計14枚のコインを集められるためです。解き方(動的計画法)この問題は動的計画法(DP)を使うと効率的に解けます。考え方はシンプルで、「あるセルに到達した時点でのコインの最大累積数」は、「そ

  2. Pythonで行列の転置を求めるプログラムの作成方法

    行列の転置とはn × n の行列 M が与えられたとき、その転置行列(transpose)を求めることを考えます。転置行列とは、行と列のインデックスを入れ替えた行列のことで、形式的には、すべての行番号 r と列番号 c に対して次の関係が成り立ちます。matrix[r][c] = matrix[c][r]つまり、元の行列の r 行 c 列にある要素は、転置後の行列では c 行 r 列へと移動します。入力例726372537出力例(転置行列)735273627解法のアプローチこの問題は、以下の手順に従って解くことができます。結果を格納するための新しいリスト M を用意します。カウンター trac