[ 백준 ] 2096 / 내려가기

金弘均·2021년 9월 15일
0

Baekjoon Online Judge

목록 보기
41/228
post-thumbnail

# Appreciation

/*
 * Problem :: 2096 / 내려가기
 *
 * Kind :: Dynamic Programming
 *
 * Insight
 * - 메모리 제한이 4MB 밖에 안되네...?
 *   딱 봐도 DP 로 풀어야 하는데
 *   A[N][3], dpMax[N][3], dpMin[N][3] 을 하면 100% 메모리 초과다
 *   + 사실, 숫자표에서 현재 줄 i 의 dpMax 또는 dpMin 을 구하려고 할 때
 *     dpMax[i][0,1,2] 와 dpMin[i][0,1,2] 는
 *     현재 숫자표에 쓰여있는 수 A[i][0,1,2] 와
 *     dpMax[i-1][0,1,2] 그리고 dpMin[i-1][0,1,2] 만 알면 구할 수 있다
 *     # 점화식은 다음과 같다
 *       dpMax[i][0] = A[i][0] + max(dpMax[i-1][0], dpMax[i-1][1])
 *       dpMax[i][1] = A[i][1] + max({dpMax[i-1][0], dpMax[i-1][1], dpMax[i-1][2]})
 *       dpMax[i][2] = A[i][2] + max(dpMax[i-1][1], dpMax[i-1][2])
 *
 *       dpMin[i][0] = A[i][0] + min(dpMin[0], dpMin[1])
 *       dpMin[i][1] = A[i][1] + min({dpMin[0], dpMin[1], dpMin[2]})
 *       dpMin[i][2] = A[i][2] + min(dpMin[i-1][1], dpMin[i-1][2])
 *       -> 현재 줄에 쓰인 점수 A[3], 이전 줄까지 갱신된 dpMax[3], dpMin[3] 만으로
 *          위의 점화식을 계산할 수 있다
 *          즉, 위의 식에 필요한 정보 외에는 저장을 해둘 필요가 없다
 *          따라서 공간복잡도를 다음처럼 줄일 수 있다
 *          A[N][3] => A[3]
 *          dpMax[N][3] => dpMax[3]
 *          dpMin[N][3] => dpMin[3]
 *
 * Point
 * - 그렇다고 위의 점화식을
 *   dpMax[0] = A[0] + max(dpMax[0], dpMax[1])
 *   처럼 계산하면 안된다
 *   + 어디까지나 dp 를 갱신할 때는 이전 줄까지의 dp 를 이용해야 한다
 *     dpMax[0] 을 위처럼 갱신후
 *     dpMax[1] = A[1] + max({dpMax[0], dpMax[1], dpMax[2]}) 을 계산하면
 *     dpMax[1] 과 dpMax[2] 는 이전 줄 기준 dp 지만
 *     dpMax[0] 은 현재 줄 기준 dp 이기 때문에 논리적으로 모순이 발생한다
 *     # 중간에 tmpMax, tmpMin 배열을 선언해서
 *       현재 줄을 기준으로 dp 를 갱신한 값을 임시로 넣은 후
 *       다시 이를 dpMax, dpMin 에 복사하는 방식으로 dp 를 갱신해주자
 */

# Code

//
//  BOJ
//  ver.C++
//
//  Created by GGlifer
//
//  Open Source

#include <iostream>
#include <cstring>

using namespace std;

#define endl '\n'

// Set up : Global Variables
/* None */

// Set up : Functions Declaration
/* None */


int main()
{
    // Set up : I/O
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    // Set up : Input
    int N; cin >> N;
    int dpMax[3], dpMin[3];
    /* 숫자표의 첫줄 초기화 */
    for (int i=0; i<3; i++) {
        int n; cin >> n;
        dpMax[i] = dpMin[i] = n;
    }
    for (int i=1; i<N; i++) {
        int A[3]; /* 숫자표의 현재 줄에 쓰여있는 점수 */
        for (int j=0; j<3; j++)
            cin >> A[j];

        // Process
        int tmpMax[3], tmpMin[3];
        /* tmpMax 계산 */
        tmpMax[0] = A[0] + max(dpMax[0], dpMax[1]);
        tmpMax[1] = A[1] + max({dpMax[0], dpMax[1], dpMax[2]});
        tmpMax[2] = A[2] + max(dpMax[1], dpMax[2]);
        /* tmpMin 계산 */
        tmpMin[0] = A[0] + min(dpMin[0], dpMin[1]);
        tmpMin[1] = A[1] + min({dpMin[0], dpMin[1], dpMin[2]});
        tmpMin[2] = A[2] + min(dpMin[1], dpMin[2]);

        /* dpMax, dpMin 갱신 */
        memcpy(dpMax, tmpMax, sizeof(tmpMax));
        memcpy(dpMin, tmpMin, sizeof(tmpMin));
    }

    // Control : Output
    cout << max({dpMax[0], dpMax[1], dpMax[2]});
    cout << ' ';
    cout << min({dpMin[0], dpMin[1], dpMin[2]});
}

// Helper Functions
/* None */
profile
이런 미친 게임을 봤나! - 옥냥이

0개의 댓글