문제 링크: https://www.acmicpc.net/problem/1931
유명한 문제입니다. Activity Selection Problem이라고도 하는데요, 유명한(well-known) 그리디 문제입니다. 알고리즘 초보인 제가 알 정도면 거의 다 알고 있다고 봐도 무방합니다. 코드포스같은데는 나올 수가 없겠죠?
그리디로 푸는 건 알겠는데, 그리디로 어떻게 풀어야 할까요? 그리디 문제는 이 점이 어렵습니다. 어떤식으로 그리디로 풀어야할지 잘 생각해봐야 합니다.
- 회의실을 짧게 쓰는 순서대로 정렬한다: X
반례: [4, 5]와 [1, 4], [5, 10]의 경우 - 먼저 시작하는 순으로 정렬한다: X
반례: [0, 10]과 [1,2], [2, 3], [3, 4], ...
정답은 '회의 종료 시간 기준 오름차순 정렬'입니다. 이렇게 정렬한 뒤, 가장 일찍 끝나는 회의(S_min)를 선택한 뒤 순서대로 체크하면서 현재 회의와 겹치는 회의는 빼고, 겹치지 않으면 회의에 넣습니다. iteration이 끝나면 회의가 몇 개 있는지 출력합니다. 정렬 + 스위핑이라고 봐도 되겠네요.
증명은 다음과 같습니다. 회의 목록 S의 최적해 중 S_min을 포함하지 않는 답이 있다고 가정해보겠습니다. 이 목록에서 첫 번째로 열리는 회의를 지운 뒤 S_min을 추가하면 이것도 역시 최적해가 됩니다. 따라서 항상 S_min을 포함하는 최적해가 존재하게 됩니다.
그리디에 관한 내용은 나중에 게시물로 정리해 올려보겠습니다.
#pragma GCC optimize ("Ofast")
#define _CRT_SECURE_NO_WARNINGS
#define _SILENCE_CXX17_C_HEADER_DEPRECATION_WARNING
#include <bits/stdc++.h>
using namespace std;
int main()
{
#ifndef ONLINE_JUDGE
freopen("input.txt", "r", stdin);
#endif
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int n;
cin >> n;
vector<pair<int, int>> vp(n);
for (auto& [from, to] : vp)
cin >> from >> to;
// 끝나는 시간 순서 기준 오름차순 정렬
sort(vp.begin(), vp.end(), [](auto& p1, auto& p2) {
if (p1.second == p2.second)
return p1.first < p2.first;
return p1.second < p2.second;
});
int counter = 1;
pair<int, int> rent = vp[0]; // from, to
for (int i = 1; i < n; ++i) {
if (vp[i].first < rent.second) { //겹침
continue;
}
else {
rent = vp[i];
++counter;
}
}
cout << counter << '\n';
return 0;
}
반응형
'Online Judge > 백준' 카테고리의 다른 글
[백준][C++] 17135: 캐슬 디펜스 (0) | 2020.07.12 |
---|---|
[백준][C++] 17070: 파이프 옮기기 1 (0) | 2020.07.12 |
[백준][C++] 5430: AC (0) | 2020.07.11 |
[백준][C++] 19236: 청소년 상어 (0) | 2020.07.11 |
[백준][C++] 1780: 종이의 개수 (0) | 2020.07.11 |