본문으로 바로가기

[BOJ 1932] (DP) 정수 삼각형 (C++)

category Algorithms/DP 2021. 8. 25. 09:30

정수 삼각형 (Silver 1)

문제

전체 문제 보기

 

1932번: 정수 삼각형

첫째 줄에 삼각형의 크기 n(1 ≤ n ≤ 500)이 주어지고, 둘째 줄부터 n+1번째 줄까지 정수 삼각형이 주어진다.

www.acmicpc.net

접근법

삼각형에서 임의의 위치 (i, j) (i: 열, j: 행)의 수를 a(i, j)라 하고, 삼각형의 꼭짓점에서 출발해서 임의의 위치 (i,j)까지 도달했을 때 경로의 최대합을 f(i, j)라고 했을 때 f(i, j)는 임의의 위치 (i,j)의 좌측 상단 (i-1, j-1)까지의 경로의 최대합과 우측 상단(i-1, j)까지 경로의 최대합에 (i, j)의 수 a(i, j) 값을 더한 값이다. 점화식으로 표현하면 다음과 같다.

\[f(i, j) = \mbox{max}(f(i-1, j), f(i-1, j-1)) + a(i, j)\]

점화식대로 연산이 호출된다면 중복계산이 많아 시간복잡도는 \(O(2^n)\)으로 상당히 커진다. 동적 계획법을 활용하여 계산량을 줄여야 하는 문제이다.

구현

아래의 방식으로 구현하였다.

  • 반복문을 활용한 bottom-up 방식으로 구현하였다.
  • 한 번 계산한 결과를 cache 배열에 저장하여 재사용하였다.
  • f(1,1)에서 f(n,n) 까지 값을 구한 후 f(n,1) 에서 f(n,n) 중 최대 값을 탐색하여 출력하였다.
#include <iostream>
#include <array>
#include <algorithm>
#define endl '\n'

using namespace std;

const int MAX = 501;
int main()
{
    //입출력 성능향상을 위한 설정
    ios_base::sync_with_stdio(false);
    cout.tie(NULL);
    cin.tie(NULL);

    int n; //1 <= n <= 500
    array<array<int, MAX>, MAX> cache{};

    cin >> n;
    for (int i = 1; i <= n; ++i)
    {
        for (int j = 1; j <= i; ++j)
        {
            int input;
            cin >> input;

            cache[i][j] = max(cache[i - 1][j], cache[i - 1][j - 1]) + input;
        }
    }

    int maxNum = 0;

    for (int i = 1; i <= n; ++i)
    {
        maxNum = max(cache[n][i], maxNum);
    }
    cout << maxNum;

    return 0;
}

성능 평가

점화식에 따르면 시간 복잡도는 \(O(2^n)\)이지만, 동적 계획법을 활용하여 한변의 길이가 \(n\)인 삼각형의 모든 위치의 값을 계산하는 \(O(n^2)\)까지 최적화하였다. 공간 복잡도 또한 모든 위치의 계산 값을 저장해 야하기 때문에 \(O(n^2)\)이다.