[ 백준 ] 11067 / 모노톤길

金弘均·2021년 9월 15일
0

Baekjoon Online Judge

목록 보기
137/228
post-thumbnail

# Appreciation

/*
 * Problem :: 11067 / 모노톤길
 *
 * Kind :: Math
 *
 * Insight
 * - 모노톤길의 특성
 *   + x 좌표가 작은 카페부터 들른다
 *   + i 번째 카페의 x 좌표와 i+1 번째 카페의 x 좌표가 서로 다르면
 *     i 번째 카페의 y 좌표와 i+1 번째 카페의 y 좌표가 서로 같아야 한다
 *   + x 좌표가 같은 카페들의 순서는
 *     y 좌표가 증가하는 순서이거나 감소하는 순서이다
 *
 * - 일단 주어진 카페들의 좌표를
 *   x 좌표가 증가하는 순서, x 좌표가 같으면 y 좌표로 증가하는 순서로 정렬해보자
 *   + ... (2,1) -> (3,1) -> [(3,3) -> (5,-1)] -> (5,1) -> (5,3) -> (6,-1) -> ..
 *     x 좌표가 달라질 때는 y 좌표가 같아야 한다
 *     # 이때 달라진 x 좌표를 기준으로 같은 x 좌표에 있는 카페들을
 *       y 좌표가 감소하는 순서로 바꾸어 주자!
 *       -> x 좌표가 증가하는 순서, x 좌표가 같으면 y 좌표가 증가하는 순서로 정렬했을 때
 *          (o = 카페, 왼쪽 숫자 = y 좌표, 아래 숫자 = x 좌표)
 *
 *          4              o       o
 *                         | \     | \
 *          3              o  |    | |
 *                         |  |    | |
 *          2          o - o   \   o |
 *                     |        |  | |
 *          1  o - o - o        |  | |
 *                              |  | |
 *                               \ |  \
 *         -1                      o   o
 *             0   1   2   3       5   6
 *
 *       -> x 좌표가 달라질 때 달라진 x 좌표를 기준으로 같은 x 좌표에 있는 카페들을
 *          y 좌표가 감소하는 순서로 바꾸어 주었을 때
 *          (o = 카페, 왼쪽 숫자 = y 좌표, 아래 숫자 = x 좌표)
 *
 *          4              o - - - o
 *                         |       |
 *          3              o       |
 *                         |       |
 *          2          o - o       o
 *                     |           |
 *          1  o - o - o           |
 *                                 |
 *                                 |
 *         -1                      o - o
 *             0   1   2   3       5   6
 *
 * Point
 * - 산책로는 항상 존재한다 <= 모노톤길이 항상 존재한다
 *
 * - 시작이 항상 (0,0) 이다
 *   + x 좌표가 0 이고 y 좌표가 음수인 카페가 주어지는 경우를 고려해주어야 한다
 *     # (0,0), (0,-1), (0,-2) 가 주어진다면
 *       정렬할 때 (0,-2) -> (0,-1) -> (0,0) 이 된다
 *       -> (0,0) -> (0,-1) -> (0,-2) 로 뒤집어 주어야 하는데
 *          이를 (-1, 0) 이라는 가상의 카페가 처음 시작때 존재한다고 가정하여 해결하였다
 *
 * - vector<int> A = {1, 2, 3};
 *   reverse(A.begin(), A.begin()+2);
 *   // A = {2, 1, 3}
 */

# Code

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

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

using namespace std;

#define endl '\n'

// Set up : Global Variables
struct Cafe { int x, y; };

// Set up : Functions Declaration
bool operator < (const Cafe &u, const Cafe &v);


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

    // Set up : Input
    int T; cin >> T;

    while (T--) {
        int N; cin >> N;
        vector<Cafe> cafes(N+1);
        for (int i=1; i<=N; i++) {
            cin >> cafes[i].x >> cafes[i].y;
        }

        // Process
        cafes[0] = {-1, 0}; /* Off by one error 해결을 위한 가상의 시작 카페 설정 */
        /* x 좌표가 증가하는 순서, x 좌표가 같으면 y 좌표가 증가하는 순서대로 정렬 
         * 주어지는 카페들의 x 좌표는 0 이상이기 때문에
         * 항상 가상의 시작 카페가 cafes[0] 이 된다 */
        sort(cafes.begin(), cafes.end()); 

        int idx = 1; /* 시작 인덱스 */
        while (idx <= N) {
            /* 현재 카페와 이전 카페의 x 좌표가 같으면 */
            if (cafes[idx].x == cafes[idx-1].x) {
                idx++; /* 올바른 모노톤길을 걷고 있음(수직 구간), 다음 카페 탐색 */
            } /* 현재 카페와 이전 카페의 x 좌표가 다를 때,
                * 현재 카페와 이전 카페의 y 좌표가 같으면 */
            else if (cafes[idx].y == cafes[idx-1].y) {
                idx++; /* 올바른 모노톤길을 걷고 있음(수평 구간), 다음 카페 탐색 */
            } /* 현재 카페와 이전 카페의 x 좌표와 y 좌표가 모두 다르면 */
            else { /* 올바른 모노톤길이 아님
                    * 현재 카페의 x 좌표를 기준으로 같은 x 좌표에 있는 카페들을
                    * y 좌표가 감소하는 순서로 만들어줌
                    * 즉, 현재 y 좌표가 증가하는 순서로 되어있으니
                    * 카페들의 순서를 뒤집어줌으로써 y 좌표가 감소하는 순서로 만들어줌 */
                auto spos = cafes.begin() + idx; /* 현재 카페의 위치 */
                int x = cafes[idx].x; /* 현재 카페의 x 좌표 */
                /* 현재 카페의 x 좌표와 같지 않은 x 좌표를 가진 카페를 만날 때까지 탐색 */
                while (++idx <= N && x == cafes[idx].x) {}
                /* 현재 카페의 x 좌표가 아닌 카페들 중 처음만난 카페의 위치 */
                auto epos = cafes.begin() + idx;
                reverse(spos, epos); /* 뒤집어줌 */
            }
        }

        // Control : Output
        int M; cin >> M;
        /* 현재 정렬된 위치가 카페의 번호가 됨 */
        for (int i=0; i<M; i++) {
            int k; cin >> k;
            cout << cafes[k].x << ' ' << cafes[k].y << endl;
        }
    }
}

// Helper Functions
bool operator < (const Cafe &u, const Cafe &v)
/* 카페 구조체 비교를 위한 함수 */
/* x 좌표가 증가하는 순서, x 좌푝 같으면 y 좌표가 증가하는 순서로 정렬 */
{
    return make_pair(u.x, u.y) < make_pair(v.x, v.y);
}
profile
이런 미친 게임을 봤나! - 옥냥이

0개의 댓글