平面最近点对(计算几何,分治)

题目链接:

P1429 平面最近点对(加强版) - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)icon-default.png?t=N176https://www.luogu.com.cn/problem/P1429

 思路:

改题使用分治法计算出平面最近点对的距离,可以先将所有的点按照x从小到大排序,接着使用分治法。

分治法:将大问题转化为类似的小问题,解决小问题后通过合并解决大问题。

这里生成了 9 个点作为例子:

按照x坐标排序后依次分别为p1,p7,p3,p2...p6,所以可以把solve(0,9)分成solve(0,4)和solve(4,9):

 

对于solve(0,4),进一步划分区间:

 

当红色部分被划分成了绿色部分和红色部分后,可以发现这两个子问题内都只有两个点了。因此直接更新最短距离 像这样依次类推更详细请看链接:

题解 P7883 【平面最近点对(加强加强版)】 - 白色过膝袜 - 洛谷博客 (luogu.com.cn)

现在假设我们已经给 (l,r) 内的点以 y 坐标为关键字排好了序。我们需要依次计算每个点对应的的绿色区域内有哪些点。容易发现,随着 y 坐标的升高,每次只会是绿色区域上面的点加入,只会是绿色区域底部的节点移出。因此也可以使用双指针解决这种问题。

 指针 L 和指针 R 之间是需要处理的数据。每次将 L 指针向右移动后,将 R 指针向右移动,直到拓展到需要处理的数据的右边界。容易发现,L 和 R 都只会移动最多 n 次,因此维护待处理数据的时间复杂度是 O(n) 的。

#include<bits/stdc++.h>
#define int long long
#define lmw ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
using namespace std;
const int N=1e6+10;
struct node{
	double x,y;
};
double dis(const node a ,const node b){
	return (double)(a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
}
bool cmpx(const node a,const node b) {
	return a.x<b.x;
}
bool cmpy(const node a,const node b){
	return a.y<b.y;
}
void solve(const vector<node>::iterator l,const vector<node>::iterator r,double &d){
	if(r-1<=l) return ;
	vector<node> q;   
	vector<node>::iterator t=l+(r-l)/2;
	double w=t->x;
	solve(l,t,d);
	solve(t,r,d);
	inplace_merge(l,t,r,cmpy);
	for(vector<node>::iterator x=l;x!=r;++x){
		if(abs(w-x->x)<=d) q.push_back(*x);
	} 
	for(vector<node>::iterator x=q.begin(),y=x;x!=q.end();++x){
		while(y!=q.end()&&y->y<=x->y+d) ++y;
		for(vector<node>::iterator z=x+1;z!=y;++z) d=min(d,dis(*x,*z));
	}
}
signed main(){
	lmw;
	int t;
	t=1;
	while(t--){
		int n;
		cin>>n;
		double ans=1e18;
		vector<node>a;
		for(int i=0;i<n;i++){
			double x,y;
			cin>>x>>y;
			a.push_back({x,y});
		}
		sort(a.begin(),a.end(),cmpx);
		solve(a.begin(),a.end(),ans);
		cout<<fixed<<setprecision(4)<<sqrt(ans)<<"\n";
	}
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值