코딩 테스트/백준
[Python] 백준 2579 계단 오르기
위시리
2025. 3. 11. 11:13
문제 분석
- 계단은 한 번에 한 계단 or 두 계산씩 오를 수 있다.
- 연속된 세 개의 계단을 모두 밟으면 x
- 시작점은 계단에 포함 x
- 마지막 도착 계단을 밟아야 한다.
- 각 계단의 점수가 주어질 때 계산 꼭대기에 도달할 때 최대 점수
- 계산의 개수는 300이하의 자연수
- 계산에 쓰여 있는 점수는 10,000이하의 자연수
풀이
- 마지막 계단은 무조건 밟아야 한다.
- 마지막 계단 -1 까지의 최대값
- 마지막 계단 -2 까지의 최대값
마지막 계단부터 거꾸로 계산?- 완탐 시 300 계단 : 1 - 2 - 4 - 8 - ... → 2^300-1 : 완탐 불가
- i번째 계단을 밟을 수 있는 경우의 수는?
- 계단의 규칙에 따르면 각 계단에 도달할 때 얻을 수 있는 최대 점수는 전의 계단과 관련이 있다.
- i번째 계단을 밟을 때 얻을 수 있는 최대 점수는
- i번째 계단을 오르기 직전 계단에서 얻을 수 있는 최대 점수와 관련이 있다. → DP
- i번째 도달할 수 있는 방법은?
- (i-2)번째 계단을 밟은 후, 2칸을 올라 i번째 계단에 도달
- (i-1)번째 계단을 밟은 후, 1칸을 올라 i번째 계단에 도달
- but 이러면 i-1번째 계단을 한 칸 올라 밟았는지, 두 칸 올라 밟았는지 알 수 없다.
- & 연속해서 세번 한 칸 오르는 경우를 막기 위해 다음과 같이 생각할 수 있다.
- i-3번째 계단을 밟은 후, 2칸 올라 i-1번째 계단에 도달한다. 그 후 1칸에 올라 I번째 계단에 도달한다.
- 이렇게 하면 i-3번째 계단을 어떻게 올라왔던 규칙에 맞게 계단을 오를 수 있다.
- DP 설계하기
(1) 관계식 구하기
DP는 앞에 계산해 놓은 값을 재활용해 뒤의 문제의 답을 구하는 방식이다.
→ 앞의 값들을 활용해 뒤의 값을 어떻게 구할 것인가
dp[ i ] = i번째 계단에서 획득할 수 있는 최대 값
arr[ i ] : i 번째 계단에서 얻을 수 있는 점수
- i-2번째 계단을 밟은 후, 2칸을 올라 i 번째 계단에 도달
- i-2번째 계단에서 얻은 최대 점수 + i번째 계단의 점수가 최댓값
- dp[i-2] + arr[ i ]
- i-3번째 계단을 밟은 후, 2칸을 올라 i-1번째 계단에 도달하고, 그 후 1칸을 올라 i 번째 계단 도달
- i-3번째 계단에서 얻은 최대 점수 + (i-1)번째 계단의 점수 +i번째 계단의 점수가 최댓값
- dp[i-3] + arr[i-1] + arr[ i ]
dp[ i ]는 1번과 2번에서 얻을 수 있는 점수 중 최댓값이다.
즉, dp[i] = max(dp[i-2], dp[i-3] + arr[i-1]) + arr[i]
만약 dp[i-1]을 고려하면, dp[i] = dp[i-1] + arr[i]를 계산해야 한다.
그러나 dp[i-1]은 이미 dp[i-2] + arr[i-1]을 포함할 수 있기 때문에, 연속해서 세 개의 계단을 밟는 경우가 발생할 위험이 있다.
예를 들어, dp[i-1]이 dp[i-2] + arr[i-1]을 사용했다면, dp[i] = dp[i-1] + arr[i]를 적용하면
👉 arr[i-2], arr[i-1], arr[i]를 연속으로 밟는 문제 발생
(2) 가장 작은 문제의 답 구해 놓기
dp[0] : 첫 계단을 밟는 경우 == arr[0]
dp[1] : 첫 계단, 두 번째 계단을 밟는 경우 == arr[0] + arr[1]
(3) 값 기록해 나가기
N까지 차례로 값 계산
이때 층계가 총 2개 이하인 경우 index out of error가 발생할 수 있으니 예외 처리**
DP의 시간 복잡도
위 방식으로 문제를 풀면 N번의 연산 필요 → O(N)
N 최대 300 → 연산 약 300개 필요
정답 코드
import sys
input = sys.stdin.readline
n = int(input())
stairs = [int(input()) for _ in range(n)]
if n < 2 :
print(stairs[n-1])
else :
dp = [0] * n
dp[0] = stairs[0]
dp[1] = stairs[0] + stairs[1]
for i in range(2, n) :
dp[i] = max(dp[i-2], dp[i-3] + stairs[i-1]) + stairs[i]
print(dp[n-1])