아이디어
처음에는 단순히 dfs 를 이용해서 문제를 해결하려 했으나 이 경우 시간초과가 발생하게 된다.
따라서 한 번 방문한 곳에 대한 정보를 저장하는 방식을 사용할 필요가 있어 dfs + dp 방식의 풀이를 적용했다.
dp[i][j] 를 (i, j) 에서 (M - 1, N - 1) 까지 갈 수 있는 경로의 수라고 정의한다면 (i, j) 의 상/하/좌/우 좌표 중 좌표값이 (i, j) 의 값보다 더 작은 dp[x][y] 들의 합이 된다.
추가로 dp 배열은 -1 로 초기화를 해주어야 하는데 그 이유는 (i, j) 에서 (M - 1, N - 1) 까지 갈 수 있는 경로의 수가 0 개인 경우도 존재하기 때문이다.
초기값이 아닌 경우 탐색한 것으로 간주하는 방식을 취할 것인데 초기값이 0이면 경로의 수가 0인 좌표는 계속해서 재탐색을 하게 된다.
풀이코드
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;
public class Main {
static int[] dx = {-1, 1, 0, 0};
static int[] dy = {0, 0, -1, 1};
static int[][] dp;
static int[][] map;
static int M;
static int N;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
M = Integer.parseInt(st.nextToken());
N = Integer.parseInt(st.nextToken());
map = new int[M][N];
dp = new int[M][N];
for (int i = 0; i < M; i++) {
st = new StringTokenizer(br.readLine());
for (int j = 0; j < N; j++) {
map[i][j] = Integer.parseInt(st.nextToken());
}
}
for (int i = 0; i < M; i++) {
Arrays.fill(dp[i], -1);
}
System.out.println(dfs(0, 0));
}
static int dfs(int i, int j) {
if (i == M - 1 & j == N - 1) {
dp[i][j] = 1;
}
if (dp[i][j] != -1) return dp[i][j];
dp[i][j] = 0;
for (int k = 0; k < 4; k++) {
int x = i + dx[k];
int y = j + dy[k];
if (x < 0 || y < 0 || x >= M || y >= N) continue;
if (map[x][y] < map[i][j]) {
dp[i][j] += dfs(x, y);
}
}
return dp[i][j];
}
}
'Algorithm > 백준 알고리즘' 카테고리의 다른 글
1005. ACM Craft (0) | 2023.10.22 |
---|---|
20542번. 받아쓰기 (0) | 2023.10.22 |
2228번. 구간 나누기 (1) | 2023.10.20 |
6064번. 카잉 달력 (0) | 2023.10.19 |
2629번. 양팔저울 (0) | 2023.10.19 |