[백준 15028] Breaking Biscuits (C#, C++) - soo:bak
작성일 :
문제 링크
설명
평면 상 볼록 다각형이 주어집니다. 다각형을 어떤 각도로 회전해도 완전히 담을 수 있는 원형 컵의 최소 지름을 구하는 문제입니다.
이는 다각형의 최소 폭과 같습니다. 최소 폭이란 다각형을 두 평행선 사이에 끼웠을 때, 그 간격이 가장 좁아지는 방향에서의 간격입니다.
접근법
다각형의 최소 폭은 항상 볼록 껍질의 어떤 변과 평행한 방향에서 나타납니다. 따라서 볼록 껍질을 구한 뒤, 각 변에 대해 그 변과 가장 먼 점까지의 수직 거리를 계산하면 됩니다.
먼저, 볼록 껍질을 구합니다. 점들을 x 좌표 기준으로 정렬하고, 정렬된 점들을 양 방향으로 순회하면서 아래 껍질과 위 껍질을 만듭니다. 새 점을 추가할 때 꺾이는 방향이 볼록하지 않으면 이전 점을 제거합니다.
다음으로, 각 변에 대해 가장 먼 점을 찾습니다. 변을 다음 변으로 이동하면 가장 먼 점도 같은 방향으로만 움직입니다. 따라서 껍질을 한 바퀴 도는 동안 가장 먼 점도 한 바퀴만 돌면 됩니다.
이후, 각 변마다 그 변에서 가장 먼 점까지의 수직 거리를 계산합니다. 이 거리는 외적의 절댓값을 변의 길이로 나눈 값입니다. 모든 변에 대해 이 값을 구하고 그 중 최솟값이 다각형의 최소 폭입니다.
최소 폭이 곧 필요한 컵의 지름이므로 이를 출력합니다.
Code
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
using System;
using System.Collections.Generic;
using System.Linq;
namespace Solution {
struct Point {
public long X, Y;
public Point(long x, long y) { X = x; Y = y; }
}
class Program {
static long Cross(Point a, Point b, Point c) {
return (b.X - a.X) * (c.Y - a.Y) - (b.Y - a.Y) * (c.X - a.X);
}
static List<Point> ConvexHull(List<Point> pts) {
pts.Sort((p1, p2) => {
var cx = p1.X.CompareTo(p2.X);
return cx != 0 ? cx : p1.Y.CompareTo(p2.Y);
});
pts = pts.Distinct().ToList();
if (pts.Count <= 2)
return pts;
var lower = new List<Point>();
foreach (var p in pts) {
while (lower.Count >= 2 && Cross(lower[lower.Count - 2], lower[lower.Count - 1], p) <= 0)
lower.RemoveAt(lower.Count - 1);
lower.Add(p);
}
var upper = new List<Point>();
for (var i = pts.Count - 1; i >= 0; i--) {
var p = pts[i];
while (upper.Count >= 2 && Cross(upper[upper.Count - 2], upper[upper.Count - 1], p) <= 0)
upper.RemoveAt(upper.Count - 1);
upper.Add(p);
}
lower.RemoveAt(lower.Count - 1);
upper.RemoveAt(upper.Count - 1);
lower.AddRange(upper);
return lower;
}
static double MinWidth(List<Point> h) {
var n = h.Count;
if (n == 2)
return 0.0;
var j = 1;
var best = double.MaxValue;
for (var i = 0; i < n; i++) {
var ni = (i + 1) % n;
var dx = h[ni].X - h[i].X;
var dy = h[ni].Y - h[i].Y;
var edgeLen = Math.Sqrt((double)dx * dx + (double)dy * dy);
while (true) {
var nj = (j + 1) % n;
var cur = Math.Abs(Cross(h[i], h[ni], h[j]));
var nxt = Math.Abs(Cross(h[i], h[ni], h[nj]));
if (nxt > cur)
j = nj;
else
break;
}
var width = Math.Abs(Cross(h[i], h[ni], h[j])) / edgeLen;
if (width < best)
best = width;
}
return best;
}
static void Main(string[] args) {
var n = int.Parse(Console.ReadLine()!);
var pts = new List<Point>(n);
for (var i = 0; i < n; i++) {
var s = Console.ReadLine()!.Split();
pts.Add(new Point(long.Parse(s[0]), long.Parse(s[1])));
}
var hull = ConvexHull(pts);
var ans = MinWidth(hull);
Console.WriteLine(ans.ToString("0.000000"));
}
}
}
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef vector<ll> vl;
struct Point {
ll x, y;
bool operator<(const Point& other) const {
if (x != other.x)
return x < other.x;
return y < other.y;
}
bool operator==(const Point& other) const {
return x == other.x && y == other.y;
}
};
typedef vector<Point> vp;
ll cross(const Point& a, const Point& b, const Point& c) {
return (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);
}
vp convexHull(vp p) {
sort(p.begin(), p.end());
p.erase(unique(p.begin(), p.end()), p.end());
if (p.size() <= 2)
return p;
vp lower, upper;
for (auto& pt : p) {
while (lower.size() >= 2 && cross(lower[lower.size() - 2], lower[lower.size() - 1], pt) <= 0)
lower.pop_back();
lower.push_back(pt);
}
for (int i = (int)p.size() - 1; i >= 0; i--) {
auto pt = p[i];
while (upper.size() >= 2 && cross(upper[upper.size() - 2], upper[upper.size() - 1], pt) <= 0)
upper.pop_back();
upper.push_back(pt);
}
lower.pop_back();
upper.pop_back();
lower.insert(lower.end(), upper.begin(), upper.end());
return lower;
}
double minWidth(const vp& h) {
int n = (int)h.size();
if (n == 2)
return 0.0;
int j = 1;
double best = numeric_limits<double>::max();
for (int i = 0; i < n; i++) {
int ni = (i + 1) % n;
ll dx = h[ni].x - h[i].x;
ll dy = h[ni].y - h[i].y;
double edgeLen = sqrt((double)dx * dx + (double)dy * dy);
while (true) {
int nj = (j + 1) % n;
ll cur = llabs(cross(h[i], h[ni], h[j]));
ll nxt = llabs(cross(h[i], h[ni], h[nj]));
if (nxt > cur)
j = nj;
else
break;
}
double width = llabs(cross(h[i], h[ni], h[j])) / edgeLen;
if (width < best)
best = width;
}
return best;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n; cin >> n;
vp p(n);
for (int i = 0; i < n; i++)
cin >> p[i].x >> p[i].y;
auto hull = convexHull(p);
double ans = minWidth(hull);
cout << fixed << setprecision(6) << ans << "\n";
return 0;
}