계단 오르기 (Silver 3)
문제
2579번: 계단 오르기
계단 오르기 게임은 계단 아래 시작점부터 계단 꼭대기에 위치한 도착점까지 가는 게임이다. <그림 1>과 같이 각각의 계단에는 일정한 점수가 쓰여 있는데 계단을 밟으면 그 계단에 쓰여 있는 점
www.acmicpc.net
접근법
이 문제는 예전에 풀었던 BOJ 2156 포도주 시식 문제와 상당히 비슷하다.(포도주 시식 풀이) 포도주 시식 문제와의 차이점은 이 문제에서는 반드시 마지막 계단을 포함해야 한다는 점이다. 이번 문제에서도 3개의 계단을 연속으로 밟을 수 없다. 그래서 임의의 위치 n에서 점수의 최댓값을 f(n), n의 점수를 a(n)이라고 했을 때 f(n)은 아래의 두 가지 경우 중 큰 값이 이다.
- 1 부터 n−3 까지의 최댓값인 f(n−3)과 a(n−2)를 포기하고 a(n−1)과 a(n)을 취하는 경우
- 1 부터 n−2 까지의 최댓값인 f(n−2)와 a(n−1)를 포기하고 a(n)을 취하는 경우
이를 점화식으로 정리하면 다음과 같다.
f(n)=max(f(n−3)+a(n−1)+a(n),f(n−2)+a(n−1))
구현
중복된 계산을 줄이기 위해서 한번 계산한 값은 cache
배열에 저장한다. 그리고 바텀업 방식으로 구현하였다.
#include <iostream>
#include <algorithm>
#include <array>
#define endl '\n'
using namespace std;
int main()
{
//입출력 성능향상을 위한 설정
ios_base::sync_with_stdio(false);
cout.tie(NULL);
cin.tie(NULL);
const int MAX = 301;
array<int, MAX> cache{};
array<int, MAX> num{};
int N; //N은 300이하의 자연수
cin >> N;
for (int i = 1; i <= N; ++i)
{
cin >> num[i];
}
cache[1] = num[1];
cache[2] = num[1] + num[2];
for (int i = 3; i <= N; ++i)
{
cache[i] = max( cache[i - 3] + num[i - 1] + num[i], cache[i - 2] + num[i]);
}
cout << cache[N];
return 0;
}
성능 평가
1부터 N까지의 최댓값을 하나씩 계산하기 때문에 시간 복잡도는 O(n)이다. 그리고 중복된 계산을 피하기 위해 모든 계산 결과를 cache
배열에 저장하고 N개 계단의 점수도 모두 저장하기 때문에 공간 복잡도 또한 O(n)이다.