【题目】
题目描述:
2 2 2 维平面上有 n n n 个木桩,黄学长有一次圈地的机会并得到圈到的土地,为了体现他的高风亮节,他要使他圈到的土地面积尽量小。圈地需要圈一个至少 3 3 3 个点的多边形,多边形的顶点就是一个木桩,圈得的土地就是这个多边形内部的土地。(因为黄学长非常的神,所以他允许圈出的第 n n n 点共线,那样面积算 0 0 0)
输入格式:
第一行一个整数 n n n,表示木桩个数。
接下来 n n n 行,每行 2 2 2 个整数表示一个木桩的坐标,坐标两两不同。
输出格式:
仅一行,表示最小圈得的土地面积,保留2位小数。
样例数据:
输入
3
0 0
0 1
1 0
输出
0.50
提示:
对于 100 % 100\% 100% 的数据, n ≤ 1000 n≤1000 n≤1000。
【分析】
暴力算法很显然, n 3 n^3 n3 枚举每个点来计算答案。
考虑一下如何优化一下暴力算法。
我们枚举两个点 a , b a,b a,b,如果把点 a , b a,b a,b 所在直线看做 y y y 轴的话,可以看出使当前面积最小的那个点就是距离当前坐标系的 y y y 轴最近的一个点(也就是在当前坐标系中横坐标绝对值最小的那个点)。
如果我们能够快速的得知最近的点的话,就可以将复杂度降低到 O ( n 2 ) O(n^2) O(n2)。
对于点,我们先按照 x x x 从小到大排序,这样可以知道各个点之间的相对关系。
把这些点两两之间求出一条直线,记录这条直线是哪两个点取到的,记录这条直线的斜率 k k k。然后按照 k k k 从小到大排序,我们可以依次按照当前 k k k 的顺序处理这些直线。
可以发现当我们在处理到直线 ( a , b ) (a,b) (a,b) 时, a , b a,b a,b 在序列中是相邻的(假设 a a a 在序列中位置在 b b b 前面),且离 ( a , b ) (a,b) (a,b) 最近的点就是序列中 a a a 左边的点或 b b b 右边的点,即可计算答案。且此时相当于 b b b 在当前坐标系中刚刚比 a a a 小(按排序定义),所以交换 a , b a,b a,b 在序列中的位置即可处理下一条直线了。
【代码】
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 1005
using namespace std;
int pos[N],id[N];
struct point
{
double x,y;
point(){}
point(double x,double y):x(x),y(y){}
point operator+(const point &a){return point(x+a.x,y+a.y);}
point operator-(const point &a){return point(x-a.x,y-a.y);}
friend double dot(const point &a,const point &b){return a.x*b.x+a.y*b.y;}
friend double cross(const point &a,const point &b){return a.x*b.y-a.y*b.x;}
friend bool operator<(const point &a,const point &b){return (a.x==b.x)?a.y<b.y:a.x<b.x;}
}p[N];
struct line
{
int s,t;
double k;
friend bool operator<(const line &a,const line &b){return a.k<b.k;}
}l[N*N];
double area(point P,line L)
{
return 0.5*fabs(cross((p[L.s]-P),(p[L.t]-P)));
}
int main()
{
int n,i,j;
scanf("%d",&n);
for(i=1;i<=n;++i)
scanf("%lf%lf",&p[i].x,&p[i].y);
sort(p+1,p+n+1);
int tot=0;
for(i=1;i<=n;++i) pos[i]=id[i]=i;
for(i=1;i<=n;++i)
{
for(j=i+1;j<=n;++j)
{
l[++tot].s=i,l[tot].t=j;
if(p[i].x==p[j].x) l[tot].k=1e18;
else l[tot].k=(p[i].y-p[j].y)/(p[i].x-p[j].x);
}
}
sort(l+1,l+tot+1);
double ans=1e18;
for(i=1;i<=tot;++i)
{
int x=pos[l[i].s];
int y=pos[l[i].t];
if(x>y) swap(x,y);
if(x>1) ans=min(ans,area(p[id[x-1]],l[i]));
if(y<n) ans=min(ans,area(p[id[y+1]],l[i]));
swap(pos[l[i].s],pos[l[i].t]);
swap(id[x],id[y]);
}
printf("%.2lf",ans);
return 0;
}