문제 : 너드인가, 너드가 아닌가? 2 (난이도 : 中)
분석
너드인가를 판단하는 매게 변수가 두 가지로 주어졌다. 너드가 아닌 경우는 두 가지 매게 변수 모두 다른 포인트보다 작을 경우이다. 이런 유형을 다룰 땐 주어진 데이터를 좌표평면 위에 그리면 쉽게 해결할 수 있다.
이렇게 좌표 평면위에 두면 할 일이 간단해진다. 지배하는 점들의 규칙을 살펴보면 x좌표가 커질수록 y좌표가 작아짐을 알 수 있다. 따라서 새로운 데이터를 추가할 때 기존 지배하는 점의 가장 오른쪽 x좌표보다 큰 지, 아니라면 y 값이 큰 지를 판단하면 된다.
STL의 map을 이용하기 좋은 문제 상황이다.
구현
map<int, int> coords;
// 새로운 점 (x, y)가 기존의 다른 점들에 지배당하는지 확인
bool isDominated(int x, int y)
{
// x보다 오른쪽에 있는 점 중 가장 왼쪽의 있는 점을 찾는다.
map<int, int>::iterator it = coords.lower_bound(x);
// 없다면 지배 당하지 않는 점.
if (it == coords.end()) return false;
// x보다 오른쪽에 있는 점 중 가장 위에 있는 점이다.
// (x, y)가 어느 점에 지배되려면 이 점에도 지배되어야함
return y < it->second;
}
// 새로운 점 (x, y)에 지배당하는 점들을 트리에서 제거
void removeDominated(int x, int y)
{
map<int, int>::iterator it = coords.lower_bound(x);
// (x, y) 보다 왼쪽에 있는 점이 없는 경우
if (it == coords.begin()) return;
--it;
while (true)
{
// (x, y) 바로 왼쪽에 오는 점을 찾는다.
// it 포인트가 (x, y) 점에 지배되지 않는다면 종료
if (it->second > y) break;
// 이전 점이 더 없으므로 it만 지우고 종료
if (it == coords.begin())
{
coords.erase(it);
break;
}
// 이전 점으로 iterator를 옮기고 it를 지운다.
else
{
map<int, int>::iterator jt = it;
--jt;
coords.erase(it);
it = jt;
}
}
}
// 새 점 (x, y)가 추가되었을 때 coords를 갱신하고,
// 다른 점에 지배당하지 않는 점들의 개수를 반환한다.
int registered(int x, int y)
{
// (x, y)가 지배당하는 경우 버린다.
if (isDominated(x, y)) return coords.size();
// 기존에 있던 점 중 (x, y)에 지배당하는 점들을 지운다.
removeDominated(x, y);
coords[x] = y;
return coords.size();
}
int main()
{
int c;
cin >> c;
while (c--)
{
int n;
cin >> n;
int ans = 0;
for (size_t i = 0; i < n; i++)
{
int x, y;
cin >> x >> y;
ans += registered(x, y);
}
cout << ans << '\n';
}
return 0;
}
'알고리즘 > 알고리즘 문제 해결 전략' 카테고리의 다른 글
[C++] 이진 트리 + 힙, 트립 (0) | 2021.01.30 |
---|---|
이진 탐색 트리(Binary Search Tree) (0) | 2021.01.17 |
[알고스팟] - 요새 (0) | 2021.01.16 |
알고스팟 - 트리 순회 순서 변경 (0) | 2021.01.10 |
알고스팟 - 외계 신호 분석 (0) | 2021.01.09 |