給定平面上 N 個點,求能包圍所有點的最短圍牆長度。圍牆需與所有點保持至少距離 L(輸入給定半徑 r),即在凸包外側擴展一條寬度為 r 的圍牆。最終長度 = 凸包周長 + 2πr(外側圓弧拼成一個完整圓)。
struct point { double x, y, angel; } p[1005], ch[1005];
double cross(point a, point b, point c) {
double x1 = b.x - a.x, y1 = b.y - a.y;
double x2 = c.x - b.x, y2 = c.y - b.y;
return x1 * y2 - x2 * y1;
}
bool cmp_angle(point a, point b) {
if (a.angel == b.angel) {
if (a.x == b.x) return a.y > b.y;
return a.x > b.x;
}
return a.angel < b.angel;
}
int main() {
int t, n; double r;
scanf("%d", &t);
while (t--) {
scanf("%d%lf", &n, &r);
for (int i = 0; i < n; ++i) scanf("%lf%lf", &p[i].x, &p[i].y);
sort(p, p + n, [](point a, point b) {
return a.y == b.y ? a.x < b.x : a.y < b.y;
});
for (int i = 1; i < n; ++i)
p[i].angel = atan2(p[i].y - p[0].y, p[i].x - p[0].x);
sort(p + 1, p + n, cmp_angle);
ch[0] = p[0]; ch[1] = p[1]; ch[2] = p[2];
int top = 3;
for (int i = 3; i < n; ++i) {
while (top > 2 && cross(ch[top-2], ch[top-1], p[i]) <= 0) --top;
ch[top++] = p[i];
}
double len = dist(ch[0], ch[top-1]);
for (int i = 1; i < top; ++i) len += dist(ch[i], ch[i-1]);
len += 2 * PI * r;
printf("%.0lf\n", len);
if (t) puts("");
}
return 0;
}
HDU 1348 是凸包模板題的典型應用,結合幾何性質「外擴圍牆長度 = 凸包周長 + 2πr」,考察 Graham Scan 實現細節:基準點選取、極角排序、叉積判斷、共線點處理。代碼簡潔高效,是計算幾何入門必刷題目。