[ 백준 ] 2170 / 선 긋기

金弘均·2021년 9월 15일
0

Baekjoon Online Judge

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

# Appreciation

/*
 * Problem :: 2170 / 선 긋기
 *
 * Kind :: Sweeping
 *
 * Insight
 * - 처음에는... 그냥 공간을 1차원 배열로 만들어서
 *   각 점이 주어질때마다 그린 후에
 *   다 탐색해보면 되지 않나... 라는 진짜 무식한 방법을 생각했다
 *   바로 때려쳤지만 말이다 <= (int) A[2*10^9+1]...
 *   + 선을 그을 때 선택한 두 점이 a,b 일 때 (a,b) 로 이를 표현하자
 *        선  - 도화지
 *     (1,3) - [1,3]
 *     (2,5) - [1,5]
 *     (6,7) - [1,5], [6,7]
 *     (3,4) - [1,5], [6,7]
 *     (5,6) - [1,7]
 *     # 도화지 위에 그어진 선들을 항상 알고 있어야 하며
 *       새로운 선을 그을 때마다 그 선의 시작점에서 끝점이
 *       다른 도화지 위에 그어진 다른 선들과 겹치는지 확인해야 한다
 *       -> 그런데... 주어지는 선의 순서는 상관없지 않나?
 *          선을 긋는 순서가 달라지더라도
 *          최종적으로 도화지에 그어진 선들을 같을 수밖에 없다
 *          => 정렬할 수 있다?!
 *
 * - 선을 긋는 순서를 정렬할 수 있다면
 *   항상 왼쪽의 선부터 그리면 도화지 위에 그어진 선들을 항상 알 필요가 없다!
 *   + 위의 입력을 시작점이 작은 순서대로, 같다면 끝점이 작은 순서대로 정렬하면
 *        선  - 도화지
 *     (1,3) - [1,3]
 *     (2,5) - [1,5]
 *     (3,4) - [1,5]
 *     (5,6) - [1,6]
 *     (6,7) - [1,7]
 *     # 여기서 만약 다음에 입력으로 (10,12) 가 주어진다면
 *       현재 도화지 위에 그어진 [1,7] 선은 이후에 덧칠될 수 없다!
 *       정렬되어있기에 이후 입력의 시작점은 10 이상일 것이기 때문이다!
 *
 * Point
 * - 이게 스위핑(Sweeping) 알고리즘인지는 사실 몰랐다...
 *   + 문제 풀고 난뒤 알고리즘 분류를 보고 알았다
 *     # 이런 종류의 풀이방식이 스위핑이구나 싶다
 */

# 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 Line { int s, e; };

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


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

    // Set up : Input
    int N; cin >> N;
    vector<Line> L(N); /* 도화지 위에 그을 선의 정보가 저장된 Vector */
    for (int i=0; i<N; i++) {
        cin >> L[i].s >> L[i].e;
    }

    // Process
    sort(L.begin(), L.end()); /* 시작점이 작은 순서대로, 같으면 끝점이 작은 순서대로 정렬 */
    int cs = L[0].s, ce = L[0].e; /* 현재 다루고 있는 도화지 위에 그어진 선 */
    int ans = 0; /* 도화지 위에 그려진 선들의 총 길이 */
    for (int i=1; i<N; i++) {
        int ls = L[i].s, le = L[i].e; /* 그릴 선의 시작점, 끝점 */
        if (ls > ce) { /* 그릴 선의 시작점이
                        * 현재 다루고 있는 도화지 위에 그어진 선의 끝점보다 크다면 */
            ans += ce-cs; /* 현재 다루고 있는 도화지 위에 그어진 선은
                           * 이후에 덧칠되지 않으므로 그 길이를 ans 에 더함 */
            cs = ls, ce = le; /* 현재 다루고 있는 도화지 위에 그어진 선을 갱신 */
        } else { /* 그릴 선의 시작점이
                  * 현재 다루고 있는 도화지 위에 그어진 선의 끝점보다 같거나 작다면 */
            ce = max(ce, le); /* 현재 다루고 있는 도화지 위에 그어진 선의
                               * 끝점을 갱신 */
        }
    } ans += ce-cs; /* 도화지 위에 그어진 마지막 선의 길이를 ans 에 더함 */

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

// Helper Functions
bool operator < (Line u, Line v)
/* Line 구조체 정렬을 위한 연산자(<) 오버로딩 */
{
    return make_pair(u.s, u.e) < make_pair(v.s, v.e);
}
profile
이런 미친 게임을 봤나! - 옥냥이
post-custom-banner

0개의 댓글