반응형
https://www.acmicpc.net/problem/21624
25/12/28
7420번과 거리 기준만 달라진 문제이다.
문제 접근 방식:
울타리와 집 사이의 맨하탄 거리($L_{1}$ norm)가 적어도 $l$이 되도록 울타리를 둘러쌀 때, 울타리의 최소 둘레를 구하는 문제이다.
만약 맨하탄 거리가 아니라 우리가 잘 아는 유클리디안 거리($L_{2}$ norm)라면 7420번 맹독 방벽 문제와 동일하다.
그리고 그 문제의 풀이는, 기존 볼록 껍질의 둘레 + 반지름이 $l$인 원의 둘레와 같았다.(볼록껍질의 꼭짓점마다 부채꼴이 붙는다고 생각하자.)
이 문제도 사실 거리 기준만 $L_{1}$으로 달라졌다 뿐이지 본질적으로 똑같은 문제이다.
$L_{1}$에서의 원의 둘레는 $4\sqrt{ 2 }l$이다.
따라서, 볼록껍질의 둘레 + $4\sqrt{ 2 }l$이 정답이 된다.
아래는 내가 위의 접근 방식과 같이 작성한 C++ 코드이다. 더보기를 누르면 확인할 수 있다.
더보기
// 21624번 Fence
// 볼록껍질
#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
#include <iomanip>
using namespace std;
#define fastio ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define endl '\n'
struct Point{
long long x, y;
Point() : x(0), y(0) {};
Point(long long x, long long y) : x(x), y(y) {};
Point operator+(const Point& p) const {return {x+p.x, y+p.y};}
Point operator-(const Point& p) const {return {x-p.x, y-p.y};}
bool operator<(const Point& p) const {
if (x == p.x) return y < p.y;
return x < p.x;
}
bool operator==(const Point& p) const {
return (x==p.x) && (y==p.y);
}
};
long long cross(const Point& p1, const Point& p2){
return p1.x*p2.y - p2.x*p1.y;
}
int ccw(const Point& p1, const Point& p2, const Point& p3){
Point p = p2-p1, q = p3-p2;
long long val = cross(p, q);
if (val > 0) return 1; // 반시계
if (val == 0) return 0; // 일직선
if (val < 0) return -1; // 시계
}
// ConvexHull with monotone chain(Three Point non-colinear)
std::vector<Point> convexHull(std::vector<Point> points){
std::vector<Point> hull;
if (points.size() < 3) return hull;
sort(points.begin(), points.end());
std::vector<Point> lowerHull, upperHull;
for (int i = 0; i < points.size(); ++i){
if (lowerHull.size() < 2){
lowerHull.push_back(points[i]);
} else {
while((lowerHull.size() >= 2) && (ccw(lowerHull[lowerHull.size()-2], lowerHull[lowerHull.size()-1], points[i]) <= 0)){
lowerHull.pop_back();
}
lowerHull.push_back(points[i]);
}
}
for (int i = 0; i < lowerHull.size(); ++i) hull.push_back(lowerHull[i]);
for (int i = 0; i < points.size(); ++i){
if (upperHull.size() < 2){
upperHull.push_back(points[i]);
} else {
while((upperHull.size() >= 2) && (ccw(upperHull[upperHull.size()-2], upperHull[upperHull.size()-1], points[i]) >= 0)){
upperHull.pop_back();
}
upperHull.push_back(points[i]);
}
}
if (upperHull.size() > 2){
for (int i = upperHull.size()-1; i > 0; --i){
hull.push_back(upperHull[i]);
}
}
if (hull.size() < 3) return std::vector<Point> ();
return hull;
}
double distance(const Point& a, const Point& b){
return sqrt((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y));
}
int main(void){
fastio
int N, L; cin >> N >> L;
vector<Point> points(N);
for (int i = 0; i < N; ++i){
cin >> points[i].x >> points[i].y;
}
vector<Point> hull = convexHull(points);
double ans = 4*sqrt(2)*L;
for (int i = 0; i < hull.size(); ++i){
ans += distance(hull[i], hull[(i+1)%hull.size()]);
}
cout << fixed << setprecision(10);
cout << ans;
return 0;
}
반응형
'알고리즘 > 백준 문제 풀이' 카테고리의 다른 글
| [C++] 15576번 큰 수 곱셈 (2) (0) | 2026.02.24 |
|---|---|
| [Python] 25214번 크림 파스타 (0) | 2026.02.24 |
| [C++] 2350번 대운하 (0) | 2026.02.22 |
| [C++] 5051번 피타고라스의 정리 (0) | 2026.02.21 |
| [C++] 31435번 기숙사 비밀번호 구하기 (0) | 2026.02.20 |