알고리즘/문제 풀이

백준 2024번: 선분 덮기

Themion 2022. 4. 13. 15:38

https://www.acmicpc.net/problem/2024

 

2024번: 선분 덮기

각 테스트 케이스는 M(1 ≤ M ≤ 50,000) 과 "Li Ri"(|Li|, |Ri| ≤ 50,000, i ≤ 100,000)쌍으로 구성이 된다. 각각은 다른 행으로 분리되어 있다. 입력은 "0 0"으로 끝난다. 모든 입력은 정수이다.

www.acmicpc.net

문제 설명만 보면 단순한 라인 스위핑 문제로 착각하기 쉽지만, 사실 이 문제는 일반적인 라인 스위핑처럼 모든 선을 사용하는 문제가 아니다. 예를 들어 두 선 [3, 5]와 [3, 8] 중 한 가지 선분을 사용할 경우 선 [3, 8]을 사용하는 것이 반드시 이득이다.

A < P < B일 때, 구간 [0, A]에서 시작하는 선들을 이용해 구간 [0, B]를 덮었고 구간 [P, Q]를 덮는 선 pq를 구간에 추가하고자 한다고 가정하자. 이 때 Q < B라면, 즉 선 pq가 지점 B 이전에 끝난다면 선 pq를 사용할 필요가 없고, 구간 [0, B]를 덮은 선 중 구간 [0, Q]에 속하는 선 pq'가 있다면 선 pq를 사용해 구간 [0, Q]를 덮은 이후 선 pq'를 사용할 필요가 없으므로 선 pq'를 제거한다. 이 과정을 구간 [0, M]을 덮을 때까지 반복하면 구간 [0, M]을 덮는 최소 선의 개수를 구할 수 있다.

#include <iostream>

using namespace std;

#define MAX_M 50000

int max(int a, int b) { return a > b ? a : b; }
int relu(int num) { return max(num, 0); }

int main() {
    // M: 덮을 구간의 길이, l, r: 각 선의 좌우 좌표, ans: 최소 선의 개수
    int M, l, r, ans = 0;
    // line[i]: i에서 시작하는 선 중 가장 긴 선의 오른쪽 좌표
    // arr[i]: 구간 [0, M]을 덮는 선분 중 i번째 선분의 오른쪽 좌표
    int line[MAX_M + 1] = { 0, }, arr[MAX_M + 1] = { 0, };

    // 덮을 구간의 길이를 입력받은 뒤
    cin >> M;
    do {
        // 각 선의 좌우 좌표를 입력받고
        cin >> l >> r;
        // 왼쪽 좌표를 기준으로 가장 긴 선의 오른쪽 좌표를 갱신
        line[relu(l)] = max(line[relu(l)], relu(r));
    // 입력이 끝날 때까지, 즉 "0 0"을 입력받을 때까지 반복
    } while (l || r);

    // 0번 좌표를 지나는 선이 존재한다면
    if (line[0]) {
        // 해당 선을 구간을 덮는 첫번째 선으로 지정
        arr[ans++] = line[0];

        // 왼쪽 좌표가 1부터 덮은 구간의 각 좌표에 대해
        for (int i = 1; i <= arr[ans - 1] && arr[ans - 1] < M; i++)
            // 해당 좌표에서 시작하는 선이 덮은 구간을 넘어설 때
            if (line[i] > arr[ans - 1]) {
                // 덮은 구간을 이루는 선 중 현재 선과 겹치는 선이 있다면 제거
                while (ans >= 2 && i <= arr[ans - 2]) ans--;
                // 현재 선을 구간을 덮을 선의 집합에 추가
                arr[ans++] = line[i];
            }
    }

    // 구간을 덮는 선의 집합 중 마지막 선의 오른쪽 좌표가 M 미만이라면 구간을 덮지 못함
    // 따라서 마지막 선이 좌표 M을 포함하는지에 따라 ans 혹은 0울 반환
    cout << ans * (arr[ans - 1] >= M) << '\n';

    return 0;
}

'알고리즘 > 문제 풀이' 카테고리의 다른 글

백준 14676번: 영우는 사기꾼?  (0) 2022.04.13
백준 2201번: 이친수 찾기  (0) 2022.04.13
백준 3151번: 합이 0  (0) 2022.02.06
백준 23349번: 졸업 사진  (0) 2022.02.03
백준 10478번: 단위  (0) 2022.01.26