
중심이 축 위에 있는 원 개 주어졌을 때 이 원들 중 서로 교차하는 부분이 있는지 확인하는 문제입니다.
이 문제의 핵심은 모든 원의 중심이 축위에 있고, 정수 좌표를 갖는다는 것입니다.
임의의 원 두 개가 있다고 가정해봅시다.
아래 그림과 같이 3가지의 경우가 나올 수 있습니다.
그림에서, 연두색 원을 , 파란색 원을 로 정하겠습니다.
이제 원의 양 끝점에서의 대소를 비교하는 것으로 교차 판별을 할 수 있게 되었습니다.
따라서 입력받는 중심 와 반지름 을 이용해,
원의 데이터를 {} 형태로 저장해둡시다.
두 개 있을 때는 비교할 수 있지만, N개의 원이 있을 때는..?
먼저, 스위핑 기법에 대하여 알아봅시다.
스위핑 기법이란, 정렬된 데이터들을 한 쪽 끝에서부터 반대쪽으로 훑어가는 기법입니다.
이 문제를 예로 설명 드리면,
왼쪽 가장 끝 원에서 시작하여 다음 원으로 이동하면서 교차 판별을 하면 모든 원에 대한 판별이 가능해집니다.
스위핑 기법을 사용하기 위해 원들을 오름차순 정렬합니다.
이렇게 정렬된 개의 원들을 왼쪽에서부터 라고 합시다.
원들의 포함 관계를 유지하기 위해 스택(stack) 자료구조를 사용합니다.
스택에 를 삽입하고, 인 에 대해 원 와 스택의 Top에 있는 원을 비교합니다.
한 원이 다른 원을 포함하면, 안쪽 원을 스택에 삽입합니다.
-> 스택의 Top에는 가장 안쪽 원, Bottom에는 가장 바깥쪽 원이 저장됩니다.
포함 관계가 없고 서로 교차하지 않는다면,
스택이 비거나 스택의 Top과 포함관계가 생길 때까지 Pop을 합니다.
Pop작업이 끝나면 현재의 원을 스택에 삽입합니다.
교차하면 반복문을 탈출하고 "NO"를 출력해주면 됩니다.
#include <iostream>
#include <algorithm>
#include <stack>
using namespace std;
int main() {
cin.tie(0)->sync_with_stdio(0);
int N, a, b;
cin >> N;
pair<int, int> circle[200000]{};
for (int i = 0; i < N; i++) {
cin >> a >> b;
circle[i] = { a - b,a + b };
}
sort(circle, circle + N);
bool success = 1;
stack<pair<int, int>> S;
S.push(circle[0]);
for (int i = 1; i < N; i++) {
pair<int, int> now = circle[i];
if (now.second < S.top().second)
S.push(now);
else if (now.first > S.top().second) {
while (!S.empty() && now.first > S.top().second)
S.pop();
if (S.empty() || now.second < S.top().second)
S.push(now);
else {
success = 0;
break;
}
}
else {
success = 0;
break;
}
}
cout << (success ? "YES" : "NO");
}
문제를 잘 추상화하면, 간단한 문제로 바뀌어서 기발하다고 생각했습니다.