[Java] 2579번: 계단 오르기 Silver 3

상곤·2025년 5월 6일

Dynamic Programming

목록 보기
1/32
post-thumbnail

문제 링크

이 문제는 거의 한 1년 전에, DP를 처음 배우면서 접했던 문제다.
알고리즘을 배운지 한 달 정도밖에 안 됐던 당시에는, 어떻게 접근해야할지 감조차 안 잡혔다.
왜냐면 계단 세 개를 연속해서 오를 수가 없기 때문에, 그럼 그것을 계속 고려해서 앞의 칸들의 최댓값을 결정지을 때 어떻게 올라왔는지(전 계단을 밟았는지, 전전 계단을 밟았는지)를 전부 기억해야되지 않나..? 라고 생각했기 때문에 그랬다.

하지만 결국에는 그것 마저도 생각해서 식을 세울 수가 있었다.
그리고 그 식을 흔히 점화식이라고 한다.
이 점화식을 세울 때는 해당 N값이 어떻게 만들어지는 지에 집중하면 쉽게 세울 수 있었다.

만약 DP가 처음이라면, SWEA 4869: 종이붙이기 이 문제를 먼저 풀어보길 추천한다!!
내가 예전에 풀었던 DP문제 풀이방법을 (이제는 안 쓰는) 네이버 블로그에 정리해놓은 글이다ㅎ 이해하기 쉬울 것이다!!

그렇다면 이 문제에서 N번 째 계단은 어떻게 결정될까?
연속하는 세 계단을 밟을 수가 없으니까, 두 경우의 수가 존재한다.

  1. 바로 전 계단(N-1)을 밟은 경우, N-3번 째 계단을 밟아야 한다.
  2. 전전 계단(N-2)을 밟은 경우, 앞의 상황을 고려하지 않아도 된다.

위 두 가지 경우에서 더 큰 값을 구하면 된다.

그럼 위의 이 두 가지만 고려하면 모든 경우를 포함할 수 있다.

왜 그렇게 될까?

우리가 N번 째 계단을 생각할 때, 세 계단을 연속해서 밟으면 안 된다는 점을 생각해서 식을 세웠다.
우리는 특정 N번째 계단을 밟을 때, 이전까지의 DP 값들이 이미 규칙을 만족하면서 최적의 해를 갖고 있다고 가정한다. 그래서 우리는 새로운 계단(N번 째 계단)을 밟을 때, 바로 직전의 상태(N-1 또는 N-2)만 고려하면 되는 것이다.

실제로 1번을 생각해보자, N-1번 째 계단을 밟고나서, N-3번 째 계단을 밟게 된다면, 중간의 N-2번 째 계단을 건너뛰었기 때문에, 규칙을 만족한다. 즉, 다시 N번째 계단에서와 같은 방식으로 최적의 선택을 하면 된다.

2번을 생각해보자, N-1번 째 계단을 건너 뛰고 N-2번 째 계단을 밟았기 때문에, N번 째 계단과 같은 상황이 된다.

즉, 규칙을 지키는 선에서 각 계단의 최적해만 구해나가다 보면 결국에 전체의 최적해를 구할 수 있는 것이다.

다른 문제에도 적용하기 위해서 좀 더 일반적으로 생각해보자면, 같은 상황이 반복되는 것을 캐치해서 점화식으로 표현하면 된다!

우리의 식은 이렇게 된다.

  1. 바로 전 계단을 밟는 경우
    DP[N] = Stair[N] + Stair[N-1] + DP[N-3]

  2. 전전 계단을 밟는 경우
    DP[N] = Stair[N] + DP[N-2]

이 둘 중 최댓값을 DP[N]으로 저장하면 된다!

그래서 최종식의 형태는 이렇게 된다.

DP[N] = Stair[N] + max(Stair[N-1] + DP[N-3], DP[N-2])

정답

import java.io.*;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        // N 입력 받기
        int N = Integer.parseInt(br.readLine());

        // 계단 입력 받기
        int[] stair = new int[N + 1];
        for (int i = 1; i <= N; i++) {
            stair[i] = Integer.parseInt(br.readLine());
        }

        // 1. 기본 세팅
        int[] DP = new int[N + 1];
        DP[1] = stair[1];
        if(N != 1) DP[2] = DP[1] + stair[2];

        // 2. DP
        for (int n = 3; n <= N; n++) {
            DP[n] = stair[n] + Math.max(stair[n - 1] + DP[n - 3], DP[n - 2]);
        }

        System.out.println(DP[N]);
    }
}
profile
🫠

0개의 댓글