卧薪尝胆,厚积薄发。
HNOI2007 最小矩形覆盖
Date: Wed Apr 03 08:07:35 CST 2019 In Category: NoCategory

Description:

给定一些点的坐标,要求求能够覆盖所有点的最小面积的矩形,输出所求矩形的面积和四个顶点坐标。
$1\leqslant n\leqslant 50000$

Solution:

旋转卡壳,点集构成的凸包一定有一条边在矩形上,于是枚举这条边,双指针维护另外三个点即可。

Code:


#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cctype>
#include<cstring>
using namespace std;
inline int rd()
{
register int res = 0,f = 1;register char c = getchar();
while(!isdigit(c)){if(c == '-')f = -1;c = getchar();}
while(isdigit(c))res = (res << 1) + (res << 3) + c - '0',c = getchar();
return res * f;
}
int n;
#define MAXN 150010
struct point
{
double x,y;
}p[MAXN];
typedef point vector;
point operator + (point a,point b){return (point){a.x + b.x,a.y + b.y};}
point operator - (point a,point b){return (point){a.x - b.x,a.y - b.y};}
double operator * (point a,point b){return a.x * b.y - a.y * b.x;}
point operator * (point a,double b){return (point){a.x * b,a.y * b};}
double area(point a,point b,point c){return fabs((b - a) * (c - a)) / 2;}
struct line
{
point p,v;
};
vector vertical(vector k){return (vector){k.y,-k.x};}
line vertical(line k){return (line){k.p,vertical(k.v)};}
point intersection(line a,line b){return b.p + b.v * ((a.v * (a.p - b.p)) / (a.v * b.v));}
point foot(point a,line b){return intersection(vertical((line){a,b.v}),b);}
point p1[MAXN],p2[MAXN];
int cnt1 = 0,cnt2 = 0;
point stack1[MAXN],stack2[MAXN];
int top1 = 0,top2 = 0;
bool cmp_x(point a,point b){return a.x < b.x;}
bool operator < (point a,point b){return (a.y == b.y ? a.x < b.x : a.y < b.y);}
double slope(point a,point b){return (a.y - b.y) / (a.x - b.x);}
point c[MAXN];
int tot = 0;
struct rect
{
point p[4];
double siz;
rect(){siz = 10000000000;}
double calc(){return area(p[0],p[1],p[2]) + area(p[0],p[2],p[3]);}
}ans;
bool operator < (rect a,rect b){return a.siz < b.siz;}
bool equal(double a,double b){return fabs(a - b) <= 1e-9;}
int main()
{
scanf("%d",&n);
for(int i = 1;i <= n;++i)scanf("%lf%lf",&p[i].x,&p[i].y);
sort(p + 1,p + 1 + n,cmp_x);
for(int i = 1;i <= n;++i)
{
if(i == 1 || p[i].x != p1[cnt1].x)p1[++cnt1] = p[i];
else if(p[i].y > p1[cnt1].y)p1[cnt1] = p[i];
else continue;
}
for(int i = 1;i <= cnt1;++i)
{
while(top1 >= 2 && slope(stack1[top1 - 1],stack1[top1]) <= slope(stack1[top1],p1[i]))--top1;
stack1[++top1] = p1[i];
}
for(int i = 1;i <= n;++i)
{
if(i == 1 || p[i].x != p2[cnt2].x)p2[++cnt2] = p[i];
else if(p[i].y < p2[cnt2].y)p2[cnt2] = p[i];
else continue;
}
for(int i = 1;i <= cnt2;++i)
{
while(top2 >= 2 && slope(stack2[top2 - 1],stack2[top2]) >= slope(stack2[top2],p2[i]))--top2;
stack2[++top2] = p2[i];
}
for(int i = 1;i <= top2;++i)c[++tot] = stack2[i];
if(stack1[top1].y != stack2[top2].y || stack1[top1].x != stack2[top2].x)c[++tot] = stack1[top1];
for(int i = top1 - 1;i >= 2;--i)c[++tot] = stack1[i];
if(stack1[1].y != stack2[1].y || stack1[1].x != stack2[1].x)c[++tot] = stack1[1];
n = tot;
for(int i = 1;i <= n;++i)p[i] = c[i];
for(int i = n + 1;i <= 2 * n;++i)p[i] = p[i - n];
for(int i = 2 * n + 1;i <= 3 * n;++i)p[i] = p[i - n];
int cura = n + 1;
while(area(p[cura + 1],p[n],p[n + 1]) >= area(p[cura],p[n],p[n + 1]))++cura;
int curl = n;while(curl > 1 && area(p[curl - 1],p[n],p[cura]) >= area(p[curl],p[n],p[cura]))--curl;
int curr = n + 1;while(curr < 3 * n && area(p[curr + 1],p[n + 1],p[cura]) >= area(p[curr],p[n + 1],p[cura]))++curr;
for(int i = n,lef = curl,rig = curr,acr = cura;i < 2 * n;++i)
{
line l = (line){p[i],p[i + 1] - p[i]};
while(acr < 3 * n && area(p[acr + 1],p[i],p[i + 1]) >= area(p[acr],p[i],p[i + 1]))
{
++acr;
point ft = foot(p[acr],l);
while((p[acr] - ft) * (p[lef] - ft) <= (p[acr] - ft) * (p[lef + 1] - ft))++lef;
while((p[rig] - ft) * (p[acr] - ft) <= (p[rig + 1] - ft) * (p[acr] - ft))++rig;
}
rect t;
t.p[0] = foot(p[lef],l);
t.p[1] = foot(p[rig],l);
t.p[2] = foot(p[rig],(line){p[acr],l.v});
t.p[3] = foot(p[lef],(line){p[acr],l.v});
t.siz = t.calc();
ans = min(ans,t);
}
printf("%.5lf\n",ans.siz);
int pos = 0;
for(int i = 1;i < 4;++i)
{
if(ans.p[i] < ans.p[pos])pos = i;
}
for(int i = 0;i < 4;++i)
{
if(equal(ans.p[(pos + i) % 4].x,0))ans.p[(pos + i) % 4].x = 0;
if(equal(ans.p[(pos + i) % 4].y,0))ans.p[(pos + i) % 4].y = 0;
printf("%.5lf %.5lf\n",ans.p[(pos + i) % 4].x,ans.p[(pos + i) % 4].y);
}
return 0;
}
Copyright © 2020 wjh15101051
ღゝ◡╹)ノ♡