본문 바로가기
알고리즘

DP 문제 시도하기(+ 백준 2579 계단오르기)

by 민챙이_99 2025. 11. 11.

1. 문제

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

 

 

2. 생각해보기(알고리즘)

A. 해당 문제가 DP 문제인 이유

1)  🧩 이전의 계단 점수의 합들을 더해서 답을 찾아야 하기 때문(단순히 분할정복 알고리즘이 아닌 이유)

2) 🥇 총 점수의 최댓값 => 최적의 해를 구해야 하기 때문

3) 🚨 놓친 부분 : 연속 횟수 제약(중복 부분 문제의 변형)
    +1은 연속해서 3번은 불가능하다. => 최대 점수를 계산할 때 반드시 직전 계단을 연속으로 몇 번 밟았는지 과거 이력을 알아야 함. 

    과거 이력을 알아야 함 = 저장해야 함 = 중복되는 부분 문제 개선필요 = DP 테이블 필요

 

 

😵‍💫 처음부터 풀려고 하니까.. 모르겠습니다..

나눠서 생각해보는 방향으로 고민해봤습니다.

(답은 아니고, 제 스스로 시도한 방법으로 적어놓았습니다.

다음과 같은 방향으로 시도하시지 마시고 어떻게 풀지는 스스로 고민해보시길 바랍니다!)

 

 

B. 한번에 +1칸 +2칸 갈 수 있는 경우의 수

DP[n] = DP[n-1] + DP[n-2]

1부터 5까지 경우의 수 구하기

n 경우의 수 케이스
1 1 (1)
2 2 (1,1), (2)
3 2 (1,2), (2,1)
4 4 (1, 2, 1), (2, 2), (2, 1, 1), (1, 1, 2)
5 6 (2, 2, 1), (1, 1, 2, 1), (2, 1, 2), (1, 2, 2)...

=> n은 결국 (n-1) + (n-2)의 경우의 수를 더해서 경우의 수가 만들어짐

 

코드로 작성해보기

const step = (num : number) => {
    if(num <= 0) return 0;
    return step(num-1) + step(num-2);
}

console.log(step(n)); // n의 앞에서 계단 개수

 

 

C. 경우의 수가 아니라 계단 점수의 합으로 변경

const stepList = [0].concat(input.slice(1).map(Number)); // 0번방 : 0, 1번방부터 input 계단 점수로 채우기
const step = (num : number) => {
     if(num <= 0) return 0;
     return stepList[num] + step(num-1) + step(num-2);
}

=> 모든 경우의 수에 대한 합이네..

 

D. 최대값을 구하려면

step(num-1), step(num-2)한 값에서 Math.max()를 사용해서 둘 중에 더 큰 값을 사용한다. 

 

 

E. 1이 연속해서 3번이 등장하면 안되는 조건 추가

=> 2가지 필요함. 
1) DP 값을 저장해야 함. (중복 관리)

2) +1을 한 케이스하고 +2를 한 케이스를 분리해서 저장해야 함. 

 

보통 탑다운 형태의 코드를 많이 작성한다고 합니다. 

 

const dp: number[][] = Array.from({ length: n + 1 }, () => [0, 0, 0]);

if (n === 1) {
     console.log(stepList[1]);
} else {
     dp[1][1] = stepList[1];
     dp[1][2] = 0; // 연속 2칸 개념 없음
     dp[2][1] = stepList[2]; // 0->2
     dp[2][2] = stepList[1] + stepList[2]; // 0->1->2

     for (let i = 3; i <= n; i++) { // 한 계단 건너(i-2)에서 오는 경우: 연속 1칸
           dp[i][1] = Math.max(dp[i - 2][1], dp[i - 2][2]) + stepList[i]; // 바로 이전(i-1)에서 오는 경우: 연속 2칸이 되므로 이전은 반드시 연속 1칸이어야 함
           dp[i][2] = dp[i - 1][1] + stepList[i];
      }
      console.log(Math.max(dp[n][1], dp[n][2]));
}

 

=> 처음 풀어보는 알고리즘이라면, 풀릴때까지 계속 생각하는게 아니라, 30분 고민해보고 다른 사람들은 어떻게 푸는지를 보고 다시 생각해보는 방향이 조금 더 도움이 될거라는 조언을 받았었습니다. 처음에는 스스로 생각해보고(물론 방향이 잘못되었기는 했지만요..) 답을 보니 왜 이렇게 풀어야 하는지 하고 제 코드는 왜 안되는지를 발견하게 되었습니다. 시간이 굉장히 많이 걸리는 일이지만, 다음 문제 풀때 길을 빠르게 잡게 되어 좋은 것 같습니다. 해당 방법으로 시도해보시기를 추천 드립니다. 

 

3. 결과

https://github.com/moonlight-duck/study-algorithms/pull/23

 

feat: 백준 2579(DP) 계단 오르기 by min-99 · Pull Request #23 · moonlight-duck/study-algorithms

📌 문제 정보 문제 링크 : https://www.acmicpc.net/problem/2579 카테고리 (예: 구현, 탐색, DP) : DP ✏️ 풀이 방법 결과 (성공/실패) : 성공 풀이 시간 : study 3h 풀이 방법 : https://min-99.tistory.com/33 참고한 글

github.com

 

제출결과

 

[참고 동영상 study]

https://www.youtube.com/watch?v=qLkFBk5-HrY&t=2s

 

'알고리즘' 카테고리의 다른 글

Greedy(탐욕 알고리즘)  (0) 2025.11.15
DP 문제(백준 1463 번)  (0) 2025.11.15
DP 개념  (0) 2025.11.11
BFS(백준 : 토마토-7576문제) 접근 방법  (0) 2025.10.30
BFS(백준 : 나이트의 이동-7562문제) 접근 방법  (0) 2025.10.30