[ 백준 ] 2304 / 창고 다각형

金弘均·2021년 9월 16일
0

Baekjoon Online Judge

목록 보기
195/228
post-thumbnail

# Appreciation

/*
 * Problem :: 2304 / 창고 다각형
 *
 * Kind :: Data Structure
 *
 * Insight
 * - 그림을 유심히 살펴보면
 *   가장 높이가 긴 기둥을 중심으로
 *   왼편 오른편 모두 그 기둥을 향하는 계단모양이다
 *   + 계단모양에서 계단을 한칸 올라간다고 생각했을 때
 *     올라간 계단의 높이보다 작은 기둥들은 계단 모양에 아무런 영향을 미치지 못한다
 *     # L=2,H=4 이고
 *       L=4,H=6 으로 계단을 한칸 올라갔는데
 *       L=5,H=3 인 기둥은 H=6 보다 짧으므로 무시된다
 *       -> 스택이구나...
 *
 * - 왼쪽부터 시작하는 스택과 오른쪽부터 시작하는 스택으로
 *   인덱스를 넣어준 뒤 <= L[i], H[i] 로 참조할 수 있도록 하기 위해서
 *   이를 이용하여 왼편 계단모양의 넓이와 오른편 계단모양의 넓이,
 *   그리고 가운데 가장 긴 기둥의 넓이를 더해서 답을 구하자
 *
 * Point
 * - 만약
 *   L=2, H=10
 *   L=4, H=10
 *   L=6, H=10
 *   인 기둥들이 있다고 하면
 *   + 아래와 같은 모양이 된다
 *     |  |  |
 *     |  |  |
 *     # 여기서 왼편 오른편을 정해야 하는데...
 *       일단 가장 긴 기둥을 맨 오른쪽 기둥이라고 하고 (세번째 기둥, i=2)
 *       왼쪽 스택은 L[i] <= H[i] 일 때 인덱스를 넣고, <= 왼쪽 스택 : (0, 1, 2)
 *       오른쪽 스택은 L[i] < H[i] 일 때 인덱스를 넣으면 <= 오른쪽 스택 : (2)
 *       겹치지 않고 왼편과 오른편을 나눌 수 있다
 *     # 만약 가장 긴 기둥을 맨 왼쪽 기둥이라고 하면 (첫번째 기둥, i=0)
 *       왼쪽 스택은 L[i] < H[i] 일 때 인덱스를 넣고, <= 왼쪽 스택 : (0)
 *       오른족 스택은 L[i] <= H[i] 일 때 인덱스를 넣으면 <= 오른쪽 스택 : (2, 1, 0)
 *       겹치지 않고 왼편과 오른편을 나눌 수 있다
 */

# Code

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


#include <iostream>
#include <stack>
#include <vector>
#include <algorithm>

using namespace std;

#define endl '\n'

// Set up : Global Variables
struct Pillar { int l, h; };

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


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

    // Set up : Input
    int N; cin >> N;
    vector<Pillar> P(N);
    for (int i=0; i<N; i++)
        cin >> P[i].l >> P[i].h;

    // Process
    sort(P.begin(), P.end()); /* 기둥들의 위치가 오름차순이 되도록 정렬 */

    stack<int> stl; /* 왼쪽 스택 */
    for (int i=0; i<N; i++) {
        /* 맨 왼쪽 기둥부터 가장 긴 기둥까지 높이가 증가하는 순서대로 인덱스가 스택에 push 됨 */
        /* 가장 높이가 긴 기둥들이 여러개라면 그 중 가장 오른쪽 기둥을 가장 긴 기둥으로 간주 */
        if (stl.empty() || P[stl.top()].h <= P[i].h) {
            stl.push(i);
        }
        /* 가장 높이가 긴 기둥들이 여러개라면 그 중 가장 왼쪽 기둥을 가장 긴 기둥으로 간주 */
        // if (stl.empty() || P[stl.top()].h < P[i].h) {
        //     stl.push(i);
        // }
    }
    stack<int> str; /* 오른쪽 스택 */
    for (int i=N-1; i>=0; i--) {
        /* 맨 오른쪽 기둥부터 가장 긴 기둥까지 높이가 증가하는 순서대로 인덱스가 스택에 push 됨 */
        /* 가장 높이가 긴 기둥들이 여러개라면 그 중 가장 오른쪽 기둥을 가장 긴 기둥으로 간주 */
        if (str.empty() || P[str.top()].h < P[i].h) {
            str.push(i);
        }
        /* 가장 높이가 긴 기둥들이 여러개라면 그 중 가장 왼쪽 기둥을 가장 긴 기둥으로 간주 */
        // if (str.empty() || P[str.top()].h <= P[i].h) {
        //     str.push(i);
        // }
    }

    int ans = P[stl.top()].h; /* 가장 긴 기둥이 차지하는 넓이 */
    /* 왼쪽 계단모양 넓이 */
    while (stl.size() > 1) { /* 기둥이 2개 이상이어야만 지붕을 만들 수 있음 */
        /* 현재 만드는 지붕에서 */
        int l1 = P[stl.top()].l; stl.pop(); /* 지붕의 오른쪽 기둥의 위치 */ 
        int l2 = P[stl.top()].l; /* 지붕의 왼쪽 기둥의 위치 */
        int h = P[stl.top()].h; /* 지붕의 높이 (왼쪽 기둥의 높이) */
        ans += (l1-l2)*h;
    }
    /* 오른쪽 계단모양 넓이 */
    while (str.size() > 1) { /* 기둥이 2개 이상이어야만 지붕을 만들 수 있음 */
        /* 현재 만드는 지붕에서 */
        int l1 = P[str.top()].l; str.pop(); /* 지붕의 왼쪽 기둥의 위치 */
        int l2 = P[str.top()].l; /* 지붕의 오른쪽 기둥의 위치 */
        int h = P[str.top()].h; /* 지붕의 높이 (오른쪽 기둥의 높이) */
        ans += (l2-l1)*h;
    }

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

// Helper Functions
bool operator < (Pillar u, Pillar v)
/* 기둥 구조체의 위치 비교(작음)를 위한 함수 */
{
    return u.l < v.l;
}
profile
이런 미친 게임을 봤나! - 옥냥이

0개의 댓글