티스토리 뷰

728x90

문제 링크

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

 

22991번: 수요응답형 버스

현대오토에버는 In-Car와 Out-Car 영역 전반의 소프트웨어와 인프라 관련 업무를 수행하는 회사이다. 현재 현대오토에버에서 수요응답형 버스(MOD)를 개발하고 있다. 수요응답형 버스는 승객이 호

www.acmicpc.net

 

풀이

버스의 최대 배정

배차 요청에 탑승 인원, 대기 가능시간이, 버스에 정원과 도착 예정 시간이 있습니다.

어떤 배차 요청에 버스가 배정되려면 (탑승 인원 $\leq$ 버스 정원), (대기 가능 시간 $\geq$ 도착 예정 시간)을 만족해야 합니다.

 

인원을 $x$축으로, 시간을 $y$축으로 두고 그래프를 그려봅시다.

검은 점은 배차 요청을, 빨간 x버스를 나타냅니다.

 

 

 

대충 보시면 알겠죠..? 가장 많은 버스를 배정하려면 각 요청 우하단의 버스 중, 가장 가까운 버스를 배정해주어야 합니다.

 

어떻게..?

1) 버스가 요청의 오른쪽 구간에 있어야 함

문제를 좀 간단히 만들어서, 시간 축이 존재하지 않는 일차원 수직선이라고 생각해봅시다.

이런 문제는 많이 풀어보셨잖아요. lower bound를 이용해서 가장 가까운 버스를 $O(logM)$만에 찾을 수 있습니다.

 

2) 버스가 요청의 아래쪽 구간에 있어야 함

배차 요청마다 칠해둔 직사각형을 잘 봅시다. 전부 바닥이 축과 닿아있죠? 

이는 어떤 요청을 처리할 때, 그보다 아래 범위의 모든 버스에 대해 마치 y축이 없는 것처럼 lower bound를 이용할 수 있다는 말이 됩니다.

 

위 두 항목을 합쳐봅시다.

요청과 버스를 모두 (시간, 인원) 순으로 정렬합니다.

시간이 낮은 순서로 요청을 처리하면, 시간이 높아질 때마다 아래 범위에 있는 버스들을 계속 누적해갈 수 있기 때문에 2번 항목을 $O(M)$의 복잡도로 처리할 수 있게 됩니다. 그렇게 누적된 버스 사이에서 lower bound로 배정될 버스를 선택할 수 있습니다.

 

map을 이용하자

사실 lower bound에는 함정이 있습니다. 배열에서 lower bound를 이용하려면 그 배열이 정렬되어있어야 합니다.

y축을 따라 버스를 누적하면서 매번 정렬하게 되면 결국 $O(M^2logM)$이 되어 의미가 없습니다. 거기다 이미 배정된 버스를 제거해야 하는데 얘도 시간복잡도가 큽니다.

 

map은 삽입, 삭제, 조회가 $O(logN)$인데 심지어 정렬까지 해주고, 자체 lower_bound도 있습니다. 치트키 자료구조..

y값인 시간은 탐색의 순서를 강제하면서 이미 고려가 되었으니 x값인 인원과 그 개수만 map에 넣어가며 관리해주면 1번 항목을 쉽게 처리할 수 있습니다.

 

자세한 구현은 코드를 참고해주세요.

 

 

정답 코드

#include <bits/stdc++.h>

#define ft first
#define sd second
#define all(x) (x).begin(), (x).end()
using namespace std;
using pii = pair<int, int>;
using vpii = vector<pii>;

int n, m;
map<int, int> busMap;
vpii req, bus;

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n >> m;
    for (int i = 0; i < n; i++) {
        int num, t;
        cin >> num >> t;
        req.emplace_back(t, num);
    }
    for (int i = 0; i < m; i++) {
        int num, t;
        cin >> num >> t;
        bus.emplace_back(t, num);
    }
    sort(all(req));
    sort(all(bus));

    int ans = 0, busIdx = 0;
    for (auto &now: req) {
        auto[y, x] = now;
        while (busIdx < m && bus[busIdx].ft <= y) {
            busMap[bus[busIdx++].sd]++;
        }
        auto b = busMap.lower_bound(x);
        if (b != busMap.end()) {
            ans++;
            if (--(b->sd) == 0) {
                busMap.erase(b);
            }
        }
    }
    cout << ans;
}
728x90
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함