Day 004-Q3 — DP基礎(2次元)

2026-04-17 緑色 / Phase 3 ★★★☆☆ 格子経路 DP

問題

H行W列のグリッド。各セルには整数スコア。左上 (0,0) から右下 (H-1, W-1) まで右または下のみ移動するとき、通過するマスのスコアの合計の最大値を求めよ。

入力形式

H W
grid[0][0] ... grid[0][W-1]
...
grid[H-1][0] ... grid[H-1][W-1]

制約

$1 \le H, W \le 100$
$-1000 \le grid[r][c] \le 1000$

入出力例

入力例 1

3 3
1 2 3
4 5 6
7 8 9

出力例 1

29

入力例 2

2 3
-1 -2 -3
-4 -5 1

出力例 2

-5

ヒント (段階的開示)

ヒント1: 方向性
「右か下のみ」→ 2次元DP。マス (r, c) への到達方法は「上から」か「左から」のみ。
ヒント2: アプローチ
dp[r][c] = max(dp[r-1][c], dp[r][c-1]) + grid[r][c]。境界処理に注意。
ヒント3: 誘導
dp[0][0] = grid[0][0]
for c in range(1, W):
    dp[0][c] = dp[0][c-1] + grid[0][c]
for r in range(1, H):
    dp[r][0] = dp[r-1][0] + grid[r][0]
for r in range(1, H):
    for c in range(1, W):
        dp[r][c] = max(dp[r-1][c], dp[r][c-1]) + grid[r][c]

模範解答 (Python)

import sys
input = sys.stdin.readline

def solve():
    H, W = map(int, input().split())
    grid = [list(map(int, input().split())) for _ in range(H)]

    NEG_INF = float('-inf')
    dp = [[NEG_INF] * W for _ in range(H)]
    dp[0][0] = grid[0][0]

    for c in range(1, W):
        dp[0][c] = dp[0][c-1] + grid[0][c]

    for r in range(1, H):
        dp[r][0] = dp[r-1][0] + grid[r][0]

    for r in range(1, H):
        for c in range(1, W):
            dp[r][c] = max(dp[r-1][c], dp[r][c-1]) + grid[r][c]

    print(dp[H-1][W-1])

solve()

Step-by-Step 解説

1状態の定義
dp[r][c] = (0,0) から (r,c) まで移動したときの最大スコア。
2遷移式
マス (r,c) には「上から」or「左から」しか来られない → max(dp[r-1][c], dp[r][c-1]) + grid[r][c]
3境界条件
最上行は左からのみ、最左列は上からのみ。-inf で初期化して「未到達」を表現。

よくあるミス

ミス原因正しい書き方
dp を 0 で初期化負スコアで誤答-inf で初期化
境界条件を忘れる範囲外アクセス最上行・最左列を別途処理
+ grid[r][c] 忘れ現在マス足し忘れ遷移式を確認

次のステップ

  • 発展: ナップサック問題(2次元DPの典型)

自己評価

自分の回答

気づき・メモ