※ 글쓴이는 취미로 코딩을 익혀보는 사람이라 정확하지 않은 내용을 담고 있을 수 있다 ※

 

이번에 볼 문제는 백준 10254번 문제인 고속도로이다.
문제는 아래 링크를 확인하자.

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

 

10254번: 고속도로

n개의 도시를 가진 나라가 있다. 이 나라에서는 도시들 중 가장 먼 두 도시 사이에 직행 고속도로를 놓으려 한다. 고속도로는 시작점과 끝점이 아닌 다른 나라를 통과해도 된다. 즉, n개의 도시

www.acmicpc.net

주어지는 점들로 convex hull을 구하고, 이를 구성하는 점들 중 가장 먼 두 점을 rotating calipers 알고리즘 등을 이용해 구하는 문제이다.

 

글쓴이는 convex hull을 Andrew's algorithm을 이용해 구했고, rotating calipus를 두 직선의 기울기의 비교를 정수 자료형의 연산만으로 수행하는 코드를 작성해 문제를 해결했다.

 

아래는 제출한 소스코드이다.

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef pair<ll, ll> pll;

int N;
pll points[200000];
vector<pll> upperhull; // leftmost x의 lowermost y부터 rightmost x의 uppermost y까지
vector<pll> lowerhull;

int CCW(pll& A, pll& B, pll& C) {
	ll ccw = (B.first - A.first) * (C.second - A.second) - (B.second - A.second) * (C.first - A.first);
	if (ccw > 0) return 1;
	else if (ccw < 0) return -1;
	else return 0;
}

void andrew_algorithm() {
	sort(points, points + N);
	
	//upperhull
	for (int i = 0; i < N; i++) {
		auto& cur = points[i];
		int cursize = upperhull.size();
		while (cursize > 1) {
			auto& L = upperhull[cursize - 2], & M = upperhull[cursize - 1];
			if (CCW(L, M, cur) != -1) upperhull.pop_back(), cursize--;
			else break;
		}
		upperhull.emplace_back(cur);
	}

	//lowerhull
	for (int i = 0; i < N; i++) {
		auto& cur = points[i];
		int cursize = lowerhull.size();
		while (cursize > 1) {
			auto& L = lowerhull[cursize - 2], & M = lowerhull[cursize - 1];
			if (CCW(L, M, cur) != 1) lowerhull.pop_back(), cursize--;
			else break;
		}
		lowerhull.emplace_back(cur);
	}
}

ll dfunc(pll& p1, pll& p2) {
	return (p1.first - p2.first) * (p1.first - p2.first) + (p1.second - p2.second) * (p1.second - p2.second);
}

void rotating_calipers() {
	int u = 0, uend = upperhull.size(), l = lowerhull.size() - 1;
	ll mx = dfunc(upperhull[u], lowerhull[l]), X1 = upperhull[u].first, Y1 = upperhull[u].second, X2 = lowerhull[l].first, Y2 = lowerhull[l].second;
	while (u < uend - 1 && l > 0) {
		if (upperhull[u].first == upperhull[u + 1].first) u++;
		else if (lowerhull[l].first == lowerhull[l - 1].first) l--;
		else {
			ll dx1 = upperhull[u + 1].first - upperhull[u].first, dy1 = upperhull[u + 1].second - upperhull[u].second;
			ll dx2 = lowerhull[l].first - lowerhull[l - 1].first, dy2 = lowerhull[l].second - lowerhull[l - 1].second;

			if (dy1 * dx2 > dx1 * dy2) u++;
			else l--;
		}

		ll tmp = dfunc(upperhull[u], lowerhull[l]);
		if (tmp > mx) mx = tmp, X1 = upperhull[u].first, Y1 = upperhull[u].second, X2 = lowerhull[l].first, Y2 = lowerhull[l].second;
	}

	while (u < uend - 1) {
		u++;
		ll tmp = dfunc(upperhull[u], lowerhull[l]);
		if (tmp > mx) mx = tmp, X1 = upperhull[u].first, Y1 = upperhull[u].second, X2 = lowerhull[l].first, Y2 = lowerhull[l].second;
	}
	while (l > 0) {
		l--;
		ll tmp = dfunc(upperhull[u], lowerhull[l]);
		if (tmp > mx) mx = tmp, X1 = upperhull[u].first, Y1 = upperhull[u].second, X2 = lowerhull[l].first, Y2 = lowerhull[l].second;
	}

	cout << X1 << ' ' << Y1 << ' ' << X2 << ' ' << Y2 << '\n';
}

int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);

	int T; cin >> T;
	while (T--) {
		upperhull.clear(), lowerhull.clear();
		cin >> N;
		for (int i = 0; i < N; i++) cin >> points[i].first >> points[i].second;
		andrew_algorithm();
		rotating_calipers();
	}
}
728x90

'BOJ' 카테고리의 다른 글

[BOJ 13242 // C++] Harps and Tails  (0) 2023.05.23
[BOJ 2244 // C++] 민코프스키 합  (0) 2023.05.22
[BOJ 9240 // C++] 로버트 후드  (0) 2023.05.20
[BOJ 1708 // C++] 볼록 껍질  (0) 2023.05.19
[BOJ 15235 // C++] Olympiad Pizza  (0) 2023.05.18

+ Recent posts