Algorithm/BOJ

[BOJ - Gold IV] 곡예 비행 / ⭕

cks._.hong 2024. 8. 18. 19:03

곡예 비행

 

1. 제출코드 (3시간 32분 43초 / DP)

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayDeque;
import java.util.StringTokenizer;

public class Main {
    static int N, M;
    static int[][] map;

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());

        map = new int[N][M];
        int[][] dp = new int[N][M];
        int[][] ddp = new int[N][M];

        for(int i = 0; i < N; i++) {
            st = new StringTokenizer(br.readLine());
            for(int j = 0; j < M; j++) {
                map[i][j] = Integer.parseInt(st.nextToken());
                dp[i][j] = Integer.MIN_VALUE;
                ddp[i][j] = Integer.MIN_VALUE;
            }
        }
        dp[N - 1][0] = map[N - 1][0];
        ddp[N - 1][M - 1] = map[N - 1][M - 1];

        for(int i = 0; i < M; i++) {
            for(int j = N - 1; j >= 0; j--) {
                // 아래
                if(i == 0) {
                    if(j == N - 1) continue;
                    dp[j][i] = dp[j + 1][i] + map[j][i];
                    // 왼쪽
                } else if(j == N - 1) {
                    if(i == 0) continue;
                    dp[j][i] = dp[j][i - 1] + map[j][i];
                } else {
                    dp[j][i] = Math.max(dp[j][i - 1], dp[j + 1][i]) + map[j][i];
                }
            }
        }

        for(int i = N - 1; i >= 0; i--) {
            for(int j = M - 1; j >= 0; j--) {
                if (i == N - 1) {
                    if(j == M - 1) continue;
                    ddp[i][j] = ddp[i][j + 1] + map[i][j];
                } else if (j == M - 1) {
                    if(i == N - 1) continue;
                    ddp[i][j] = ddp[i + 1][j] + map[i][j];
                } else {
                    ddp[i][j] = Math.max(ddp[i][j + 1], ddp[i + 1][j]) + map[i][j];
                }
            }
        }

        int answer = Integer.MIN_VALUE;

        for(int i = 0; i < N ; i++) {
            for(int j = 0; j < M; j++) {
                answer = Math.max(answer, dp[i][j] + ddp[i][j]);
            }
        }
        System.out.println(answer);
    }
}

 

2. 구현 로직

DP 배열에 상승할 때의 경우와 하강할 때의 경우를 나누고 각 칸마다 가질 수 있는 최대값을 저장한다. 그러고 두개의 DP 배열을 더하면 최댓값을 구할 수 있게 된다.

  1. 2개의 DP배열을 생성하고 초기화
  2. 상승 DP 배열은 N - 1, 0부터 시작이므로 map[N-1][0] 값을 초기화하고 하강 DP 배열은 N-1,M-1부터 시작해서 0,0까지 탐색하는 것으로 map[N-1][M-1]을 초기화
  3. 상승의 경우 왼쪽이랑 밑에서 오는 경우만 고려하면 된다.
  4. 하강의 경우 역으로 생각하여 오른쪽이랑 밑에서 오는 경우만 고려하면 된다.
  5. 2개의 DP 배열 값을 구하고 dp[i][j] + ddp[i][j]의 최댓값을 구하면 정답

 

3. 유의할 점

  • 처음에는 BFS를 이용해서 로직을 구현했지만 시간초과가 발생했다. N과 M의 범위를 체크해서 시간복잡도를 고려했어야 했는데 그러지 못했다.