DP 가이드 (8/11)

이전 편: [코딩테스트] 7. 선형 DP

다음 편: [코딩테스트] 9. LIS

DP 유형별 패턴 시리즈

선형 DP · 격자 DP · LIS · 배낭 문제 · 실전 패턴과 면접 대비

DP 가이드 : 기본 개념설계 전략유형별 패턴

격자 DP는 2차원 배열에서 특정 위치에 도달하는 최적값을 구하는 패턴이다. 행과 열을 인덱스로 쓰므로 dp[i][j] 형태가 기본이다. 이동 방향 제약이 핵심이다.

기본 형태

N×M 격자에서 (0,0)에서 출발해 (N-1, M-1)에 도달하려 한다. 오른쪽과 아래쪽으로만 이동할 수 있을 때 경로 위 숫자의 최대 합은?

상태 정의 : dp[i][j] = (0,0)에서 (i,j)에 도달할 때의 최대 합

점화식 : (i,j)에 도달하는 방법은 위에서 오거나, 왼쪽에서 오거나.

dp[i][j] = max(dp[i-1][j], dp[i][j-1]) + grid[i][j]
flowchart TD A["dp[i-1][j]\n위에서"] --> C["dp[i][j]"] B["dp[i][j-1]\n왼쪽에서"] --> C
dp[0][0] = grid[0][0];

for (int i = 0; i < n; i++) {
    for (int j = 0; j < m; j++) {
        if (i == 0 && j == 0) continue;
        int fromUp   = (i > 0) ? dp[i-1][j] : Integer.MIN_VALUE;
        int fromLeft = (j > 0) ? dp[i][j-1] : Integer.MIN_VALUE;
        dp[i][j] = Math.max(fromUp, fromLeft) + grid[i][j];
    }
}

위에서 오거나 왼쪽에서 오거나 — 두 경우 중 더 큰 값을 선택한다.

경계 처리

격자 DP에서 자주 실수하는 부분이 첫 행과 첫 열이다.

  • 첫 행(i=0) : 위에서 오는 경로가 없다. 왼쪽에서만 올 수 있다
  • 첫 열(j=0) : 왼쪽에서 오는 경로가 없다. 위에서만 올 수 있다

코드에서 (i > 0) 조건으로 처리하거나, 첫 행과 첫 열을 별도로 초기화하는 방법이 있다.

// 첫 행 초기화 (위에서 올 수 없으므로 왼쪽에서만)
for (int j = 1; j < m; j++) {
    dp[0][j] = dp[0][j-1] + grid[0][j];
}

// 첫 열 초기화 (왼쪽에서 올 수 없으므로 위에서만)
for (int i = 1; i < n; i++) {
    dp[i][0] = dp[i-1][0] + grid[i][0];
}

// 나머지
for (int i = 1; i < n; i++) {
    for (int j = 1; j < m; j++) {
        dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]) + grid[i][j];
    }
}

첫 행과 첫 열을 미리 처리해두면 본문 로직이 단순해진다.

이동 방향이 복잡해지면

오른쪽/아래만 이동하는 문제는 탐색 순서가 자연스럽게 위→아래, 왼→오른이다. 그런데 이동 방향이 추가되면 어떻게 될까.

좌우 이동이 허용되지만 위로는 갈 수 없고 재방문도 금지라면, 단순한 2D 점화식으로는 처리하기 어렵다. 이런 경우에는 행 단위로 분리해서 방향별 배열을 따로 만드는 기법을 쓴다.

이동 제약 → 처리 방향 힌트

"위로 갈 수 없다" → 행 단위로 순서대로 처리 가능

"오른쪽으로만" → 열 오름차순 처리

이동 제약은 탐색 순서의 힌트다.

다음 : LIS