본문 바로가기
코딩테스트!(프로그래머스 & 백준)/백준 - C++

백준 2579번 계단오르기 (C++)

by Lee_story_.. 2022. 9. 13.
728x90

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

 

2579번: 계단 오르기

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

www.acmicpc.net

문제!


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

<그림 1>

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

<그림 2>

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

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

따라서 첫 번째 계단을 밟고 이어 두 번째 계단이나, 세 번째 계단으로 오를 수 있다. 하지만, 첫 번째 계단을 밟고 이어 네 번째 계단으로 올라가거나, 첫 번째, 두 번째, 세 번째 계단을 연속해서 모두 밟을 수는 없다.

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


요약하면 조건에 맞춰서 계단을 오를텐데 밟을수 있는 계단의 최대합을 구하는 문제로

조건은

1. 한계단 또는 두계단을 오를수있다는것

2. 연속으로 한계단 3번은 불가능

3. 마지막 도착지점에는 무조건 도착해야된다는것

 

이중 2번이 좀 어려울것 같네요...

 

 

 

일단 첫번째 오답 코드


이 코드에서 저는 조건 2번을 따르기 위해서 1칸 움직인 횟수를(count) 세어 주었고

1칸뛰는 것과 2칸 뛰는것을 따로 두고 생각해보았습니다.

 

for (int i = 2; i < N; i++) {
        if (count == 2) {
            dp[i][0] = 0;
            dp[i][1] = step[i] + max(dp[i - 2][0], dp[i - 2][1]); // 2칸 올라감
            count = 0;
        }
        else {
            count += 1;
            dp[i][0] = step[i] + max(dp[i - 1][0], dp[i - 1][1]);
            dp[i][1] = step[i] + max(dp[i - 2][0], dp[i - 2][1]);
        }
        
    }

 

그랬더니 어디선가 틀렸다고 뜨네요...

 

 

 

전체코드!

더보기
#include <iostream>
#include <vector>

using namespace std;

vector <int> step(301);
int dp[302][2]={0}; // 1칸뛰기, 2칸뛰기



int main() {
    int N;
    int answer = 0;
    int count = 0;
    cin >> N;

    
    
    for (int i = 0; i < N; i++) {//  계단받기
        cin >> step[i];
    }


    if (N <= 1) {
        cout << step[0] << endl;
        return 0;
    }

    dp[0][0] = step[0]; // 첫번째계단 점수?
    dp[0][1] = 0;

    dp[1][0] = step[0] + step[1];// 두번째 계단
    dp[1][1] = step[1];
    count = 2;
    
    for (int i = 2; i < N; i++) {
        if (count == 2) {
            dp[i][0] = 0;
            dp[i][1] = step[i] + max(dp[i - 2][0], dp[i - 2][1]); // 2칸 올라감
            count = 0;
        }
        else {
            count += 1;
            dp[i][0] = step[i] + max(dp[i - 1][0], dp[i - 1][1]);
            dp[i][1] = step[i] + max(dp[i - 2][0], dp[i - 2][1]);
        }
        
    }

    answer = max(dp[N - 1][0], dp[N - 1][1]);
    
    cout << answer << endl;

}

 

 

그래서 좀 찾아보고 다시 코드를 만들어 보았습니다

 

 

 

진짜 시작!


일단 1차원 배열로 dp를 선언해줍니다.

vector <int> step(301);
int dp[302]={0}; // 1칸뛰기

 

그리고 1칸뛰어간것과 2칸뛰어간것의 최댓값만 계속 저장해줍시다.

    dp[0] = step[0]; // 첫번째계단 점수?
    dp[1] = max(step[1], step[0] + step[1]);// 두번째 계단
    dp[2]=max(step[0] + step[2], step[1] + step[2]);// 세번째 계단

 

 

그리고 여기서..... 위에서 제가 카운트로 계속 세어 주면서 판별했던것과는 완전히 다르게

계단3칸을

2+ 1 (현재칸에 2칸을 뛰어 옴)

2 +1+1 (현재칸3칸전에 2칸을 뛰고, 1칸을 뛰어 옴)

 

이런 식으로 묶어서 생각 해주었네요....

for (int i = 3; i < N; i++) {
        dp[i] = max(dp[i - 2] + step[i], dp[i - 3] + step[i - 1] + step[i]);
    }

 

엄청난....

 

그 이후는 일반적인 답 출력....

    answer = dp[N - 1];
    
    cout << answer << endl;

 

 

열심히 풀었는데 아쉽게 묶어 생각하지는 못했네요... 

 

 

ALL

#include <iostream>
#include <vector>

using namespace std;

vector <int> step(301);
int dp[302]={0}; // 1칸뛰기



int main() {
    int N;
    int answer = 0;

    cin >> N;

    
    
    for (int i = 0; i < N; i++) {//  계단받기
        cin >> step[i];
    }


    if (N <= 1) {
        cout << step[0] << endl;
        return 0;
    }

    dp[0] = step[0]; // 첫번째계단 점수?

    dp[1] = max(step[1], step[0] + step[1]);// 두번째 계단


    dp[2]=max(step[0] + step[2], step[1] + step[2]);// 세번째 계단
    

    for (int i = 3; i < N; i++) {
        dp[i] = max(dp[i - 2] + step[i], dp[i - 3] + step[i - 1] + step[i]);
    }

    answer = dp[N - 1];
    
    cout << answer << endl;

}

 

 

 

 

틀린점이 있다면 댓 달아주세요!

댓글