[백준] 계단 오르기 - 2579

김준영·2023년 8월 14일

코딩테스트

목록 보기
4/13
post-thumbnail

링크

https://www.acmicpc.net/problem/2579

문제

계단 오르기 게임은 계단 아래 시작점부터 계단 꼭대기에 위치한 도착점까지 가는 게임이다. <그림 1>과 같이 각각의 계단에는 일정한 점수가 쓰여 있는데 계단을 밟으면 그 계단에 쓰여 있는 점수를 얻게 된다.

<그림 1>

예를 들어 <그림 2>와 같이 시작점에서부터 첫 번째, 두 번째, 네 번째, 여섯 번째 계단을 밟아 도착점에 도달하면 총 점수는 10 + 20 + 25 + 20 = 75점이 된다.

<그림 2>

계단 오르는 데는 다음과 같은 규칙이 있다.

  1. 계단은 한 번에 한 계단씩 또는 두 계단씩 오를 수 있다. 즉, 한 계단을 밟으면서 이어서 다음 계단이나, 다음 다음 계단으로 오를 수 있다.
  2. 연속된 세 개의 계단을 모두 밟아서는 안 된다. 단, 시작점은 계단에 포함되지 않는다.
  3. 마지막 도착 계단은 반드시 밟아야 한다.
    따라서 첫 번째 계단을 밟고 이어 두 번째 계단이나, 세 번째 계단으로 오를 수 있다. 하지만, 첫 번째 계단을 밟고 이어 네 번째 계단으로 올라가거나, 첫 번째, 두 번째, 세 번째 계단을 연속해서 모두 밟을 수는 없다.

각 계단에 쓰여 있는 점수가 주어질 때 이 게임에서 얻을 수 있는 총 점수의 최댓값을 구하는 프로그램을 작성하시오.

입력

입력의 첫째 줄에 계단의 개수가 주어진다.

둘째 줄부터 한 줄에 하나씩 제일 아래에 놓인 계단부터 순서대로 각 계단에 쓰여 있는 점수가 주어진다. 계단의 개수는 300이하의 자연수이고, 계단에 쓰여 있는 점수는 10,000이하의 자연수이다.

출력

첫째 줄에 계단 오르기 게임에서 얻을 수 있는 총 점수의 최댓값을 출력한다.

문제 정리

만약 현재 세 번째(15) 계단에 있다고 가정 했을 때, 2가지 경우가 있다.
1. 첫 번째 계단(10)에서 두 계단을 오른 경우
2. 두 번째 계단(20)에서 한 계단을 오른 경우

그리고, 현재의 계단에서 다음 경우로 넘어갈 때 2가지 경우가 있다.
1. 한 계단을 오르는 경우 -> 네 번째 계단(25) 도착
2. 두 계단을 오르는 경우 -> 다섯번 째 계단(10) 도착
이때, 이전 계단에서 한 계단만 오른경우. 즉, 첫 번째 계단에서 현재 계단으로 온 경우에는 다음번에 두 계단을 올라야한다.

정리하면
1. 이전에 몇 칸을 오르던, 다음에 두 칸을 오르는 데에는 제약이 없다.
2. 다음에 한 칸만 오르고 싶다면, 이전에 두 칸을 올라야한다.

풀이

DP를 사용하여 풀었다.
3개의 정수형 배열을 사용했다. 길이는 모두 계단의 길이와 같다.
1. 계단의 점수를 저장하는 배열
2. 이전에 한 계단을 오른 경우의 누적 점수를 저장하는 배열
3. 이전에 두 계단을 오른 경우의 누적 점수를 저장하는 배열

배열을 이용해 아래와 같이 값을 저장할 수 있다.

A의 한 계단 전 누적합을 Y, 두 계단 전을 X라 했을 때

B의 한 계단 전은 A이다.
단, A 이전에 두 계단을 올랐어야 한다. 즉, B의 한 계단 전은 X+A로 표현할 수 있다.

C의 두 계단 전은 A이다.
A 이전에 한 계단 또는 두 계단을 올랐을 경우로 나누어서 둘 중 큰 값으로 표현한다.

이러한 식으로 계단 점수 배열을 순회하며 해당 계단 값으로 상위 계단의 값들을 추론해 큰 값으로 저장한다.

코드

import java.io.BufferedReader;
import java.io.InputStreamReader;

class Main {
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        
        // input & init | N & steps
        int n = Integer.parseInt(br.readLine());
        int[] steps = new int[n];
        int[] one = new int[n]; // 이전의 계단이 한 칸 전인 경우, 이전 계단들의 합
        int[] two = new int[n]; // 이전의 계단이 두 칸 전인 경우, 이전 계단들의 합
        
        for(int i=0; i<n; i++)
            steps[i] = Integer.parseInt(br.readLine());
        
        // solve |
        for(int i=0; i<n-1; i++){
            one[i+1] = steps[i] + two[i];
            if(i<n-2){
                two[i+2] = Math.max(steps[i]+one[i],steps[i]+two[i]);
            }
        }
        
        System.out.println(Math.max(steps[n-1]+one[n-1], steps[n-1]+two[n-1]));
    }
}

0개의 댓글