平面最近点对

平面最近点对

给平面上 \(N\) 个点,求最近点对之间距离。 \(1\le N\le 2\cdot 10^5\).

算法

考虑用分治解决。

将所有坐标按 \(x\) 排序,分治求出两边的最小答案 \(ans\) 。对答案有贡献的点,横坐标与中间点横坐标的差值不超过 \(ans\) . 把这些点拉出来按 \(y\) 排序,每个点找与该点 \(y\) 差值不超过 \(ans\) 的点统计答案。这样的点不会超过 \(7\) 个。复杂度 \(O(n\log n)\) .

以下为洛谷P1429的代码

#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
namespace io {
	const int SIZE=(1<<21)+1;
	char ibuf[SIZE],*iS,*iT,c;
	#define gc()(iS==iT?(iT=(iS=ibuf)+fread(ibuf,1,SIZE,stdin),(iS==iT?EOF:*iS++)):*iS++)
	template <class I>
	inline void gi (I &x){
		for(c=gc();c<'0'||c>'9';c=gc());
		for(x=0;c<='9'&&c>='0';c=gc()) x=(x<<1)+(x<<3)+(c&15);
	}
}
using io::gi;
const int N=200005;
struct node {
	int x,y;
} a[N];
bool operator < (node s, node t) {
	return s.x<t.x;
} int n,s[N];
double dis(node s, node t) {
	return sqrt(1ll*(s.x-t.x)*(s.x-t.x)+1ll*(s.y-t.y)*(s.y-t.y));
}
bool cmp(int s, int t) {
	return a[s].y<a[t].y;
}
double solve(int l, int r)
{
	if(r-l==1) return dis(a[l],a[r]);
	if(r-l==2) return min(dis(a[l],a[r]),min(dis(a[l],a[l+1]),dis(a[l+1],a[r])));
	int mid=l+r>>1,id=0;
	double mn=min(solve(l,mid),solve(mid+1,r));
	for(int i=mid;i>=l&&a[mid].x-a[i].x<=mn;--i) s[++id]=i;
	for(int i=mid+1;i<=r&&a[i].x-a[mid+1].x<=mn;++i) s[++id]=i;
	sort(s+1,s+1+id,cmp);
	for(int i=1;i<=id;++i)
		for(int j=i+1;j<=id&&a[s[j]].y-a[s[i]].y<=mn;++j) mn=min(mn,dis(a[s[i]],a[s[j]]));
	return mn;
}
int main()
{
	gi(n);
	for(int i=1;i<=n;++i) gi(a[i].x),gi(a[i].y);
	sort(a+1,a+1+n);
	printf("%.4lf",solve(1,n));
}

例题

题意

给定一个长度为 \(n\) 的数列 \(a_i\) ,定义函数 \(f(i,j)=(i-j)^2+g(i,j)^2(1\le i< j\le n)\) ,其中 \(g(i,j)=\sum_{k=i+1}^j a_k\) .

\(\min\{ f(i,j) \}\) .

\(n\le 10^5, |a_i|\le 10^4\)

题解

将上面的式子定义为平面上两点距离,即为求最近点对距离。

#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
namespace io {
	const int SIZE=(1<<21)+1;
	char ibuf[SIZE],*iS,*iT,c;
	#define gc()(iS==iT?(iT=(iS=ibuf)+fread(ibuf,1,SIZE,stdin),(iS==iT?EOF:*iS++)):*iS++)
	template <class I>
	inline void gi (I &x){
		for(c=gc();c<'0'||c>'9';c=gc());
		for(x=0;c<='9'&&c>='0';c=gc()) x=(x<<1)+(x<<3)+(c&15);
	}
}
using io::gi;
const int N=200005;
struct node {
	int x,y;
} a[N];
bool operator < (node s, node t) {
	return s.x<t.x;
} int n,s[N];
double dis(node s, node t) {
	return sqrt(1ll*(s.x-t.x)*(s.x-t.x)+1ll*(s.y-t.y)*(s.y-t.y));
}
bool cmp(int s, int t) {
	return a[s].y<a[t].y;
}
double solve(int l, int r)
{
	if(r-l==1) return dis(a[l],a[r]);
	if(r-l==2) return min(dis(a[l],a[r]),min(dis(a[l],a[l+1]),dis(a[l+1],a[r])));
	int mid=l+r>>1,id=0;
	double mn=min(solve(l,mid),solve(mid+1,r));
	for(int i=mid;i>=l&&a[mid].x-a[i].x<=mn;--i) s[++id]=i;
	for(int i=mid+1;i<=r&&a[i].x-a[mid+1].x<=mn;++i) s[++id]=i;
	sort(s+1,s+1+id,cmp);
	for(int i=1;i<=id;++i)
		for(int j=i+1;j<=id&&a[s[j]].y-a[s[i]].y<=mn;++j) mn=min(mn,dis(a[s[i]],a[s[j]]));
	return mn;
}
int main()
{
	gi(n);
	for(int i=1;i<=n;++i) gi(a[i].x),gi(a[i].y);
	sort(a+1,a+1+n);
	printf("%.4lf",solve(1,n));
}
posted @ 2019-02-28 20:43  x_faraway_x  阅读(129)  评论(0)    收藏  举报