题目描述:
$Xaviera$ 现在遇到了一个有趣的问题。
平面上有 $N$ 个点,$Xaviera$ 想找出周长最小的三角形。
由于点非常多,分布也非常乱,所以 $Xaviera$ 想请你来解决这个问题。
为了减小问题的难度,这里的三角形也包括共线的三点。
算法标签:分治
思路:
每次不断分治下去,每一维只需要对于两区间最靠近中间仍有可能小于现有答案的部分进行统计。
以下代码:
#include<bits/stdc++.h> #define il inline #define db double #define _(d) while(d(isdigit(ch=getchar()))) using namespace std; const int N=2e5+5; const db eps=1e-8; int n,b[N],cnt; db ans; struct node{ int x,y; }t[N]; il int read(){ int x,f=1;char ch; _(!)ch=='-'?f=-1:f;x=ch^48; _()x=(x<<1)+(x<<3)+(ch^48); return f*x; } bool cmp(node t1,node t2){ return t1.x<t2.x; } bool cmp1(int t1,int t2){ return t[t1].y<t[t2].y; } il db pf(db x){ return x*x; } il db dis(int a,int b){ return sqrt(pf(t[a].x-t[b].x)+pf(t[a].y-t[b].y)); } il void solve(int l,int r){ if(l==r)return; int mid=(l+r)>>1; solve(l,mid);solve(mid+1,r); cnt=0;b[++cnt]=mid; for(int i=mid-1;i>=l;i--)if(t[mid].x-t[i].x<ans)b[++cnt]=i;else break; for(int i=mid+1;i<=r;i++)if(t[i].x-t[mid].x<ans)b[++cnt]=i;else break; sort(b+1,b+1+cnt,cmp1); long double dis1,dis2,dis3; for(int i=1;i<cnt-1;i++){ for(int j=i+1;j<cnt;j++){ if(t[b[j]].y-t[b[i]].y>ans)break; dis1=dis(b[i],b[j]); if(dis1>ans)continue; for(int k=j+1;k<=cnt;k++){ if(t[b[k]].y-t[b[j]].y>ans)break; dis2=dis(b[i],b[k]); if(dis2>ans)continue; dis3=dis(b[j],b[k]); if(dis1+dis2+dis3<ans)ans=dis1+dis2+dis3; } } } } int main() { n=read(); for(int i=1;i<=n;i++)t[i].x=read(),t[i].y=read(); sort(t+1,t+1+n,cmp); ans=dis(1,2)+dis(1,3)+dis(2,3); solve(1,n); printf("%lf ",ans); return 0; }