2018.10.03 bzoj3707: 圈地(计算几何)

传送门
计算几何好题。


本蒟蒻表示不看题解只会 O ( n 3 ) O(n^3) O(n3)
正解是先考虑把直线按照斜率从小到大排序,然后把点按坐标排序。
这样每次枚举到直线 ( a , b ) (a,b) (a,b)时,离直线 a , b a,b a,b最近的点只能在 a , b a,b a,b在点序列中相邻的两个点上取到,然后在转过这条直线之后, ( a , b ) (a,b) (a,b)关于直线的相对位置会发生变化,所以每次转过之后交换 a , b a,b a,b就行了。
代码:

#include
#define N 1005
using namespace std;
inline int read(){
	int ans=0,w=1;
	char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
	while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
	return ans*w;
}
struct Pot{double x,y;}p[N];
struct Line{int a,b;double k;}l[N*N];
int n,tot=0,num[N],pred[N];
double ans=1e18;
inline Pot operator-(Pot a,Pot b){return (Pot){a.x-b.x,a.y-b.y};}
inline double operator*(Pot a,Pot b){return a.x*b.y-a.y*b.x;}
inline bool Cmp(Pot a,Pot b){return a.x==b.x?a.y<b.y:a.x<b.x;}
inline bool cmp(Line a,Line b){return a.k<b.k;}
inline double calc(Pot a,Line b){return fabs((p[b.a]-a)*(p[b.b]-a))*0.5;} 
int main(){
	n=read();
	for(int i=1;i<=n;++i)p[i].x=read()*1.0,p[i].y=read()*1.0,pred[i]=num[i]=i;
	sort(p+1,p+n+1,Cmp);
	for(int i=1;i<n;++i)for(int j=i+1;j<=n;++j)l[++tot]=(Line){i,j,p[i].x==p[j].x?1e18:(double)((double)p[i].y-p[j].y)/((double)p[i].x-p[j].x)};
	sort(l+1,l+tot+1,cmp);
	for(int i=1;i<=tot;++i){
		int a=num[l[i].a],b=num[l[i].b];
		if(a>b)swap(a,b);
		if(a^1)ans=min(ans,calc(p[pred[a-1]],l[i]));
		if(b^n)ans=min(ans,calc(p[pred[b+1]],l[i]));
		swap(num[l[i].a],num[l[i].b]),swap(pred[a],pred[b]);
	}
	printf("%.2lf",ans);
	return 0;
}

你可能感兴趣的:(#,计算几何)