[ 백준 ] 2296 / 건물짓기

金弘均·2021년 9월 15일
0

Baekjoon Online Judge

목록 보기
82/228
post-thumbnail
post-custom-banner

# Appreciation

/*
 * Problem :: 2296 / 건물짓기
 *
 * Kind :: Dynamic Programming
 *
 * Insight
 * - 1,3 사분면에만 건물짓기
 *   2,4 사분면에만 건물짓기
 *   + 건물의 좌표는 달라지지 않으니 일단
 *     x좌표 오름차순으로 정렬해주자 (하는김에 x좌표도 같으면 y좌표 오름차순으로 정렬함)
 *     -> 정렬된 건물들을 앞에서부터 번호를 붙여 1~N번 이라고 한다면
 *        dp[i][$13] = 1~i번 건물들 중 1,3 사분면에만 지었을 때 얻을 수 있는 최대 이익
 *        => 이는 dp[1~(i-1)][$13] 중에서 i번째 건물을 지을 수 있는지 알아보면 된다
 *        dp[i][$24] = 1~i번 건물들 중 2,4 사분면에만 지었을 때 얻을 수 있는 최대 이익
 *        => 이는 dp[1~(i-1)][$24] 중에서 i번째 건물을 지을 수 있는지 알아보면 된다
 *
 * - 일단 x좌표 오름차순으로 건물이 정렬되어있기 때문에
 *   i번 건물을 짓기 위해서는 1~(i-1)번 건물의 y좌표와 i번 건물의 y좌표를 비교해야 한다
 *   + 정렬된 건물들이 저장된 배열을 B, j=1~(i-1) 이라고 하면
 *     B[i].y > B[j].y => 1 사분면에 i번 건물짓기 가능
 *     B[i].y < B[j].y => 4 사분면에 i번 건물짓기 가능
 *
 * Point
 * - 건물을 좌표기준으로 정렬해서
 *   y좌표 비교만으로 1 또는 4 사분면에 지을 수 있는지 확인하는 것이 중요
 *   + 지어진 건물 사이사이에 끼워넣어 건물을 지으려고 하면
 *     지을 수 있는지 확인하는 과정이 굉장히 괴로워진다
 */

# Code

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

#include <iostream>
#include <algorithm>

using namespace std;

#define endl '\n'

// Set up : Global Variables
struct Building { int x, y, c; };
enum { $13, $24 };

// Set up : Functions Declaration
bool operator < (Building u, Building v);


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

    // Set up : Input
    int N; cin >> N;
    Building B[N];
    for (int i=0; i<N; i++)
        cin >> B[i].x >> B[i].y >> B[i].c;

    // Process
    /* 건물들을 x좌표 오름차순으로 정렬 */
    sort(B, B+N);

    /* dp[i][$13] = 1~i번 건물들 중 1,3 사분면에만 지었을 때 얻을 수 있는 최대 이익
     * dp[i][$24] = 1~i번 건물들 중 2,4 사분면에만 지었을 때 얻을 수 있는 최대 이익 */
    int dp[N][2];
    for (int i=0; i<N; i++) {
        dp[i][$13] = dp[i][$24] = B[i].c; /* 각각의 건물들을 하나만 지었을 경우 */
    }

    for (int i=0; i<N; i++) {
        for (int j=0; j<i; j++) {
            if (B[j].y < B[i].y) { /* j번 건물의 y좌표 < i번 건물의 x좌표 */
                /* j번 건물 기준 1 사분면에 i번 건물을 지을 수 있음 */
                dp[i][$13] = max(dp[i][$13], dp[j][$13]+B[i].c);
            }
            if (B[j].y > B[i].y) { /* j번 건물의 y좌표 > i번 건물의 x좌표 */
                /* j번 건물 기준 4 사분면에 i번 건물을 지을 수 있음 */
                dp[i][$24] = max(dp[i][$24], dp[j][$24]+B[i].c);
            }
        }
    }

    /* dp 값들 중 최댓값이 얻을 수 있는 최대 이익 */
    int ans = *max_element(&dp[0][0], &dp[N-1][2]);

    // Control : Output
    cout << ans << endl;
}

// Helper Functions
bool operator < (Building u, Building v)
/* Building 구조체 정렬을 위한 함수 */
{
    /* x좌표 오름차순으로, 만약 x좌표가 같다면 y좌표 오름차순으로 정렬 */
    return make_pair(u.x, u.y) < make_pair(v.x, v.y);
}
profile
이런 미친 게임을 봤나! - 옥냥이
post-custom-banner

0개의 댓글