
이번 포스트에서는 폭우로 물에 잠긴 격자에서 집(1, 1)에서 학교(m, n)까지 갈 수 있는 최단 경로의 개수를 구하는 문제를 다루었다. 최단 경로의 개수를 세는 문제는 전형적인 동적 계획법(DP) 문제로, 이전 지점의 경로 수를 합산하여 현재 지점의 경로 수를 계산했다. 특히 경로 개수가 매우 커질 수 있어 나머지 연산()을 적용하고, 웅덩이(장애물) 지점은 경로 개수를 0으로 처리하는 것이 핵심이었다.
격자형 맵에서 한 방향으로만 이동하는 경우의 수는 동적 계획법 (Dynamic Programming, DP)을 적용하기 가장 좋은 형태이다.
for 루프를 돌며 순서로 테이블을 채운다.#include <string>
#include <vector>
using namespace std;
// 나머지 연산을 위한 상수 (1,000,000,007)
const int MOD = 1e9 + 7;
int solution(int m, int n, vector<vector<int>> puddles) {
// DP 테이블 선언 (크기 : n+1 x m+1 크기)
vector<vector<long long>> dp(n + 1, vector<long long>(m + 1, 0));
// 물 웅덩이 위치를 테이블에 -1로 표시
for (const auto& puddle : puddles) {
dp[puddle[1]][puddle[0]] = -1;
}
// DP 테이블 채우기 (i: 세로, j: 가로)
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
// 시작 지점 테이블 설정
if (i == 1 && j == 1) {
dp[1][1] = 1;
continue;
}
// 현재 위치가 웅덩이인 경우 테이블 설정
if (dp[i][j] == -1) {
dp[i][j] = 0;
continue;
}
// 위쪽(i-1)과 왼쪽(j-1)에서 오는 경로 수 합산
// 인덱스 0 참조 시 0값이 더해짐
long long up = dp[i - 1][j];
long long left = dp[i][j - 1];
// 덧셈 후 나머지 연산 적용 (오버플로우 방지)
dp[i][j] = (up + left) % MOD;
}
}
return dp[n][m];
}
int로 선언했을 때, 경로의 개수가 를 초과할 경우 오버플로우가 발생할 가능성이 있었다.int의 최댓값()을 넘어서면 잘못된 결과가 나온다.long long으로 변경했다.(up + left) % MOD 형태로 작성하여, 덧셈을 수행하는 과정에서 안정성을 확보했다.| 항목 | 내용 |
|---|---|
| 유형 | Dynamic Programming (DP) / Grid Pathfinding |
| 체감 난이도 | 중 (DP의 기본을 이해하고 나머지 연산 및 웅덩이 처리만 주의하면 됨) |
| 복잡도 | 시간: , 공간: |
| 새로 배운 것 | DP 문제에서 큰 수에 대한 나머지 연산을 할 때는 long long을 사용하여 합산 과정에서 오버플로우가 발생하지 않도록 방지하는 것이 중요하다는 것을 다시 한번 확인했다. 💡 |