【模板】 平面最近点对 题解

题目:P1492

考虑分治。先对横坐标进行排序,用solve(l,r)表示表示横坐标在(l,r)内的点之间最小距离。我们将区间(l,r)分成两部分,则我们要求的最小距离可以分成三个部分:

1.左边的点之间的最小距离

2.右边的点之间的最小距离

3.左边的点到右边的的点之间的最小距离

先分别递归求求解solve(l,mid)与solve(mid+1,r),这样就解决了1,2两部分。下面来求解第三部分。设由1,2部分得到的最小距离为d,显而易见,我们只需要考虑横坐标在区间(mid-d,mid+d)的点。

我们将这部分点暴力求出,再将这些点按纵坐标排序,直接暴力求出每对点对间的距离。根据主定理,我们有 f(n)=2f(n/2)+O(nlogn)=O(nlog2n) 。

注意到分治的过程其实与归并排序一致,所以我们可以在对纵坐标归并排序时顺便递归求解,复杂度可以下降到O(nlogn)。

O(nlog2n) 代码

 

#include<bits/stdc++.h>
using namespace std;
#define il inline
#define ll long long
#define Inf 1e10
int read() {
    int s=0,w=1; char ch=getchar();
    while(ch<'0' || ch>'9') { if(ch=='-') w=-1; ch=getchar();}
    while(ch>='0' && ch<='9') s=s*10+ch-'0',ch=getchar();
    return s*w;
} 
const int N=4e5+10;
int n;
struct node{
	double x,y;
} a[N],b[N];
bool cmp(node p1,node p2) {
	return p1.x<p2.x;
}
bool cmp2(node p1,node p2) {
	return p1.y<p2.y;
}
double ans;
double dist(node p1,node p2) {
	return sqrt((ll)(p1.x-p2.x)*(p1.x-p2.x)+(ll)((p1.y-p2.y)*(p1.y-p2.y)));
}
double solve(int l,int r) {
	if(l==r) return Inf;
	int mid=(l+r)/2;
	double d=min(solve(l,mid),solve(mid+1,r));
	int js=0;
	for(int i=l;i<=r;i++) if(fabs(a[i].x-a[mid].x) < d) b[++js]=a[i];
	sort(b+1,b+js+1,cmp2);
	for(int i=1;i<=js;i++) {
		for(int j=i+1;j<=js;j++) {
			if(b[j].y-b[i].y >= d) break;
		    d=min(dist(b[i],b[j]),d);
		    d=min(dist(b[i],b[j]),d);
		}
	}
	return d;
}
int main() {
	n=read();
	for(int i=1;i<=n;i++) scanf("%lf %lf",&a[i].x,&a[i].y);
	sort(a+1,a+n+1,cmp);
	ans=solve(1,n);
	printf("%.4lf",ans);
	return 0;
}

  

posted @ 2021-10-12 20:56  残碑小筑  阅读(53)  评论(0)    收藏  举报
faults = { minSize : 10, maxSize : 20, newOn : 1000, flakeColor : "#FFFFFF" /* 此处可以定义雪花颜色,若要白色可以改为#FFFFFF */ }, options = $.extend({}, defaults, options); var interval= setInterval( function(){ var startPositionLeft = Math.random() * documentWidth - 100, startOpacity = 0.5 + Math.random(), sizeFlake = options.minSize + Math.random() * options.maxSize, endPositionTop = documentHeight - 200, endPositionLeft = startPositionLeft - 500 + Math.random() * 500, durationFall = documentHeight * 10 + Math.random() * 5000; $flake.clone().appendTo('body').css({ left: startPositionLeft, opacity: startOpacity, 'font-size': sizeFlake, color: options.flakeColor }).animate({ top: endPositionTop, left: endPositionLeft, opacity: 0.2 },durationFall,'linear',function(){ $(this).remove() }); }, options.newOn); }; })(jQuery); $(function(){ $.fn.snow({ minSize: 5, /* 定义雪花最小尺寸 */ maxSize: 80,/* 定义雪花最大尺寸 */ newOn: 200 /* 定义密集程度,数字越小越密集 */ }); });