UVA10173 Smallest Bounding Rectangle 最小面積矩形覆蓋
阿新 • • 發佈:2018-12-29
\(\color{#0066ff}{題目描述}\)
給定n(>0)二維點的笛卡爾座標,編寫一個程式,計算其最小邊界矩形的面積(包含所有給定點的最小矩形)。
輸入檔案可以包含多個測試樣例。每個測試樣例從包含一個正數的行開始。 整數N(<1001),表示該測試樣例中的點的數量。接下來的n行各包含兩個實數,分別給出一個點的x和y座標。輸入最後包含一個值為0的測試樣例,該值必須不被處理。
對於輸入中的每個測試樣例都輸出一行,包含最小邊界矩形的面積,小數點後四捨五入到第四位。
\(\color{#0066ff}{輸入格式}\)
\(\color{#0066ff}{輸出格式}\)
\(\color{#0066ff}{輸入樣例}\)
3
-3.000 5.000
7.000 9.000
17.000 5.000
4
10.000 10.000
10.000 20.000
20.000 20.000
20.000 10.000
0
\(\color{#0066ff}{輸出樣例}\)
80.0000
100.0000
\(\color{#0066ff}{資料範圍與提示}\)
none
\(\color{#0066ff}{題解}\)
旋轉卡殼
首先先求一遍凸包
對於最小面積外接矩形,顯然至少有一條邊與凸包重合,就列舉那條邊(底邊)
對於上面的邊,通過叉積叉出面積判斷最高位置,找到上邊
對於左邊,用點積,找到最大點積(投影最長,那麼最靠左),右邊指標從左邊開始找投影最短
每次移動底邊,然後更新上左右,來更新ans
#include <bits/stdc++.h> #define _ 0 #define LL long long inline LL in() { LL x = 0, f = 1; char ch; while(!isdigit(ch = getchar()))(ch == '-') && (f = -f); while(isdigit(ch)) x = x * 10 + (ch ^ 48), ch = getchar(); return x * f; } struct node { double x,y; node(double x = 0, double y = 0):x(x), y(y) {} node operator - (const node &b) const { return node(x - b.x, y - b.y); } double operator ^ (const node &b) const { return x * b.y - y * b.x; } double operator * (const node &b) const { return x * b.x + y * b.y; } double mo() { return sqrt(x * x + y * y); } double jj() const { return atan2(y, x); } }; const int maxn = 10005; node e[maxn], v[maxn]; int n,top; double S(node a,node b,node c) { return (b - a) ^ (c - a); } bool cmp(const node &a, const node &b) { return (a.jj() < b.jj() || (a.jj() == b.jj() && (a - e[0]).mo() < (b - e[0]).mo())); } void tubao() { int min = 0; for(int i = 0; i < n; i++) if(e[i].y < e[min].y || (e[i].y == e[min].y && e[i].x < e[min].x)) min = i; std::swap(e[0], e[min]); for(int i = 1; i < n; i++) e[i] = e[i] - e[0]; e[0] = 0; std::sort(e + 1, e + n, cmp); v[0] = e[0], v[1] = e[1]; for(int i = top = 2; i < n; i++) { while((top > 1) && (S(v[top - 2], v[top - 1], e[i]) <= 0)) top--; v[top++] = e[i]; } v[top] = e[0]; } double C(node a,node b,node c) { return (c - a) * (b - a); } double rotate() { if(top < 3) return 0; int l = 1, u = 1, r; double a, b, c, ans = 1e20; for(int i = 0; i < top; i++) { while(S(v[i], v[i + 1], v[u + 1]) > S(v[i], v[i + 1], v[u])) u = (u + 1) % top; while(C(v[i], v[i + 1], v[l + 1]) > C(v[i], v[i + 1], v[l])) l = (l + 1) % top; if(!i) r = l; while(C(v[i], v[i + 1], v[r + 1]) <= C(v[i], v[i + 1], v[r])) r = (r + 1) % top; a = S(v[i], v[i + 1], v[u]); b = C(v[i], v[i + 1], v[l]) - C(v[i], v[i + 1], v[r]); c = C(v[i], v[i + 1], v[i + 1]); ans = std::min(ans, a * b / c); } return ans; } int main() { while("fuck") { n = in(); if(!n) break; for(int i = 0; i < n; i++) scanf("%lf%lf", &e[i].x, &e[i].y); tubao(); printf("%.4lf\n", rotate()); } return 0; }