【BZOJ3707】圈地

Description

2维平面上有n个木桩,黄学长有一次圈地的机会并得到圈到的土地,为了体现他的高风亮节,他要使他圈到的土地面积尽量小。圈地需要圈一个至少3个点的多边形,多边形的顶点就是一个木桩,圈得的土地就是这个多边形内部的土地。(因为黄学长非常的神,所以他允许圈出的第n点共线,那样面积算0)

Input

第一行一个整数n,表示木桩个数。
接下来n行,每行2个整数表示一个木桩的坐标,坐标两两不同。

Output

仅一行,表示最小圈得的土地面积,保留2位小数。

Sample Input

3
0 0
0 1
1 0

Sample Output

0.50

HINT

对于100%的数据,n<=1000。

题解:假如我们已经确定了三角形的一条边,那么面积可以表示成 边长*高/2,如果我们将所选的边当做y轴,那么显然第3个点应取|x|最小的点。问题是如何快速确定|x|最小的点。

有一个结论(难想),就是将所有直线按照极角排序(斜率也行),将所有点按y排序(相当于所选的边是x轴),此时所有点距离直线的相对位置是确定的。我们枚举每条直线,当我们从ai,bi枚举到ai+1,bi+1时,只有ai,bi的相对位置发生了改变,其余点的相对位置均不改变。(相对位置指的是以所选直线为y轴后,x的大小关系。这个结论自己画画应该就能理解)

于是我们用桶维护每个点的相对位置即可。

 

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn=1010;
int n,tot;
int s[maxn],pos[maxn];
double ans;
struct point
{
	double x,y;
	point () {}
	point (double a,double b){x=a,y=b;}
	point operator + (const point &a) const {return point(x+a.x,y+a.y);}
	point operator - (const point &a) const {return point(x-a.x,y-a.y);}
	double operator * (const point &a) const {return x*a.y-y*a.x;}
}p[maxn];
struct line
{
	double k;
	int a,b;
}l[1000000];
inline int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<'0'||gc>'9')	{if(gc=='-')f=-f;	gc=getchar();}
	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
	return ret*f;
}
bool cmpy(point a,point b)
{
	return a.y<b.y;
}
bool cmpk(line a,line b)
{
	return a.k<b.k;
}
void calc(int a,int b,int c)
{
	double S=fabs((p[b]-p[a])*(p[c]-p[a])/2);
	ans=min(ans,S);
}
int main()
{
	n=rd();
	int i,j;
	for(i=1;i<=n;i++)	p[i].x=rd(),p[i].y=rd();
	sort(p+1,p+n+1,cmpy);
	for(i=1;i<=n;i++)	s[i]=pos[i]=i;
	for(i=1;i<=n;i++)	for(j=i+1;j<=n;j++)	l[++tot].k=atan2(p[j].y-p[i].y,p[j].x-p[i].x),l[tot].a=i,l[tot].b=j;
	sort(l+1,l+tot+1,cmpk);
	ans=999999999;
	for(i=1;i<=tot;i++)
	{
		if(pos[l[i].a]>pos[l[i].b])	swap(l[i].a,l[i].b);
		if(pos[l[i].a]>1)	calc(s[pos[l[i].a]-1],l[i].a,l[i].b);
		if(pos[l[i].b]<n)	calc(s[pos[l[i].b]+1],l[i].a,l[i].b);
		swap(pos[l[i].a],pos[l[i].b]);
		s[pos[l[i].a]]=l[i].a,s[pos[l[i].b]]=l[i].b;
	}
	printf("%.2lf",ans);
	return 0;
}

 

| 欢迎来原网站坐坐! >原文链接<