-
[백준] 13310번 - 먼 별알고리즘/백준 2025. 2. 9. 04:16
문제
https://www.acmicpc.net/problem/13310
풀이
캘리퍼스 + 삼분 탐색
각 시간마다 찍힌 별들 중 최대 거리에 대해 최소값을 찾는 문제
f(x)에 대한 삼분 탐색이지만 f(x)가 캘리퍼스 구현 ㅇㅇ..., distance 반환값을 int로 해놓고 발견못해서 고통받았다.
+ 계속 틀리길래 혹시해서 탐색 구현을 아래처럼 변경했더니 pass됨, 왜 그런지는 좀 생각해봐야 할듯
// 틀림 if (sim(lm) < sim(rm)) { right = rm; } else { left = lm; } // Pass if (sim(lm) > sim(rm)) { left = lm; } else { right = rm; }
코드
#include <iostream> #include <vector> #include <queue> #include <stack> #include <algorithm> #include <map> #include <cmath> using namespace std; struct Input { long long x, y, dx, dy; }; vector<Input> stars; struct Dot { long long x, y; }; int N, T; vector<Dot> input; stack<Dot> s; vector<Dot> convexHull; int cross(Dot& a, Dot& b, Dot& c) { Dot line1 = { b.x - a.x, b.y - a.y }; Dot line2 = { c.x - b.x, c.y - b.y }; long long r = line1.x * line2.y - line1.y * line2.x; if (r < 0) return -1; if (r > 0) return 1; return 0; } int cross2(Dot& a, Dot& b, Dot& c, Dot& d) { Dot line1 = { b.x - a.x, b.y - a.y }; Dot line2 = { d.x - c.x, d.y - c.y }; long long r = line1.x * line2.y - line1.y * line2.x; if (r < 0) return -1; if (r > 0) return 1; return 0; } long long getDistance(Dot a) { return (input[0].x - a.x) * (input[0].x - a.x) + (input[0].y - a.y) * (input[0].y - a.y); } bool cmp(Dot& a, Dot& b) { int r = cross(input[0], a, b); if (r > 0) return 1; if (r == 0) return getDistance(a) < getDistance(b); return 0; } long long sim(int day) { input.clear(); convexHull.clear(); // 현재 시간에 별들의 위치 정보 계산 for (int i = 0; i < stars.size(); ++i) { input.push_back({ stars[i].x + stars[i].dx * day, stars[i].y + stars[i].dy * day, }); } // convex hull 계산 Dot temp; for (int i = 1; i < input.size(); ++i) { if (input[i].x < input[0].x) { temp = input[0]; input[0] = input[i]; input[i] = temp; } else if (input[i].x == input[0].x && input[i].y < input[0].y) { temp = input[0]; input[0] = input[i]; input[i] = temp; } } sort(input.begin() + 1, input.end(), cmp); s.push(input[0]); s.push(input[1]); for (int i = 2; i < input.size(); ++i) { while (s.size() >= 2) { Dot prev = s.top(); s.pop(); Dot prev2 = s.top(); if (cross(prev2, prev, input[i]) > 0) { s.push(prev); break; } } s.push(input[i]); } // 캘리퍼스 계산 while (!s.empty()) { //cout << s.top().x << ", " << s.top().y << "\n"; convexHull.push_back(s.top()); s.pop(); } int index = 1; long long maxDis = 0; int cs = convexHull.size(); for (int i = 0; i < cs; ++i) { while (cross2(convexHull[i], convexHull[(i + 1) % cs], convexHull[index % cs], convexHull[(index + 1) % cs]) < 0) { long long currDis = (convexHull[i].x - convexHull[index % cs].x) * (convexHull[i].x - convexHull[index % cs].x) + (convexHull[i].y - convexHull[index % cs].y) * (convexHull[i].y - convexHull[index % cs].y); if (maxDis < currDis) { maxDis = currDis; } index++; } long long currDis = (convexHull[i].x - convexHull[index % cs].x) * (convexHull[i].x - convexHull[index % cs].x) + (convexHull[i].y - convexHull[index % cs].y) * (convexHull[i].y - convexHull[index % cs].y); if (maxDis < currDis) { maxDis = currDis; } } //maxDis. //cout << "maxDis: " << maxDis << "\n"; return maxDis; } int main() { ios::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL); cin >> N >> T; int x, y, dx, dy; for (int i = 0; i < N; ++i) { cin >> x >> y >> dx >> dy; stars.push_back({ x, y, dx, dy }); } long long shortestDistance = 8000000000000000000; int shortestDay = 0; if (N == 2) { for (int i = 0; i <= T; ++i) { Dot star1 = { stars[0].x + stars[0].dx * i, stars[0].y + stars[0].dy * i }; Dot star2 = { stars[1].x + stars[1].dx * i, stars[1].y + stars[1].dy * i }; long long currDis = (star1.x - star2.x) * (star1.x - star2.x) + (star1.y - star2.y) * (star1.y - star2.y); //cout << currDis << "\n"; if (currDis < shortestDistance) { shortestDistance = currDis; shortestDay = i; } } cout << shortestDay << "\n" << shortestDistance; } else { if (T <= 20) { for (int i = 0; i <= T; ++i) { long long ret = sim(i); if (ret < shortestDistance) { shortestDistance = ret; shortestDay = i; } } cout << shortestDay << "\n" << shortestDistance; } else { //삼분 int left = 0; int right = T; while (right - left >= 3) { int lm = (left * 2 + right) / 3; int rm = (right * 2 + left) / 3; if (sim(lm) > sim(rm)) { left = lm; } else{ right = rm; } } for (int i = left; i < left + 3; ++i) { long long ret = sim(i); //cout << i << ": " << ret << "\n"; if (ret < shortestDistance) { shortestDistance = ret; shortestDay = i; } } cout << shortestDay << "\n" << shortestDistance; } } return 0; }
'알고리즘 > 백준' 카테고리의 다른 글
[백준] 24024번 - 삼색 그래프 (0) 2025.02.23 [백준] 3679 - 단순 다각형 (0) 2025.01.25 [백준] 12752번 - 도시들 (1) 2025.01.04 [백준] 5670번 - 휴대폰 자판 (0) 2024.12.22 [백준] 1854 - K번째 최단경로 찾기 (0) 2024.12.07