传送门
计算几何好题。
本蒟蒻表示不看题解只会
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<bits/stdc++.h>
#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;
}

这篇博客介绍了计算几何中的经典问题——圈地。博主分享了自己初次尝试时的O(n^3)解决方案,并详细解释了优化思路:通过将直线按斜率排序,点按坐标排序,可以更高效地解决这个问题。在枚举直线过程中,利用相邻点的特性更新最近点,并在转过直线后调整直线相对位置,以此降低时间复杂度。
953

被折叠的 条评论
为什么被折叠?



