首页 > 其他分享 >分治-平面最近点对问题

分治-平面最近点对问题

时间:2024-01-05 15:47:26浏览次数:27  
标签:node int 分治 db 最近 ax ay 平面 bx

oi wiki 中该问题的讲解。


1.P1257 平面上的最接近点对

基础款,暴力可过。


2.P1429 平面最近点对(加强版

正常款,玄学版本也能过(题解第一个做法,不过最初没卡这种方法的话应该随机情况下能过绝大多数点)。

分治解决,将集合每次分成两部分,两个部分本别先求出集合内部的最小点对的答案 d;然后找到 mid 将这个集合划分成两部分,先按照一维排序并只保留离这个划分线距离不超过 d 的。

然后按照另一维排序,枚举处理。

实际上就有很多剪枝了。sort 排序的程序复杂度是 \(O(n \log^2 n)\),分治排序的程序复杂度是严格 \(O(n \log n)\) 的。

我不会证明复杂度,但题解区有写的很好的证明博客。请大家移步去看。

Code:

#include<bits/stdc++.h>
#define db double
using namespace std;
const int N=1e6+10;
int n;
int t[N];
struct node{int x,y;}s[N];
db dis(int p,int q){
	int ax=s[p].x,ay=s[p].y;
	int bx=s[q].x,by=s[q].y;
	return sqrt(1.0*(ax-bx)*(ax-bx)+1.0*(ay-by)*(ay-by));
}
bool cmp(node a,node b){
	if(a.x==b.x) return a.y<b.y;
	return a.x<b.x;
}
bool cmp2(int a,int b){
	return s[a].y<s[b].y;
}
db mer(int l,int r){
	db d=1e18;
	if(l==r) return d;
	if(l+1==r) return dis(l,r);
	int mid=(l+r)>>1;
	db d1=mer(l,mid),d2=mer(mid+1,r);
	d=min(d1,d2);
	int k=0;
	for(int i=l;i<=r;i++)
		if(fabs(s[mid].x-s[i].x)<d) t[++k]=i;
	sort(t+1,t+k+1,cmp2);
	for(int i=1;i<=k;i++){
		for(int j=i+1;j<=k;j++){
			if(s[t[j]].y-s[t[i]].y>=d) break;
			d=min(d,dis(t[i],t[j]));
		}
	}
	return d;
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d%d",&s[i].x,&s[i].y);
	sort(s+1,s+n+1,cmp);
	printf("%.4lf",mer(1,n));
	return 0;
}

3.P7883 平面最近点对(加强加强版)

实际上和上题的区别只是卡掉了那个玄学做法。

点击查看代码
#include<bits/stdc++.h>
#define db double
using namespace std;
const int N=1e6+10;
int n;
int t[N];
struct node{int x,y;}s[N];
db dis(int p,int q){
	int ax=s[p].x,ay=s[p].y;
	int bx=s[q].x,by=s[q].y;
	return sqrt(1.0*(ax-bx)*(ax-bx)+1.0*(ay-by)*(ay-by));
}
bool cmp(node a,node b){
	if(a.x==b.x) return a.y<b.y;
	return a.x<b.x;
}
bool cmp2(int a,int b){
	return s[a].y<s[b].y;
}
db mer(int l,int r){
	db d=1e18;
	if(l==r) return d;
	if(l+1==r) return dis(l,r);
	int mid=(l+r)>>1;
	db d1=mer(l,mid),d2=mer(mid+1,r);
	d=min(d1,d2);
	int k=0;
	for(int i=l;i<=r;i++)
		if(fabs(s[mid].x-s[i].x)<d) t[++k]=i;
	sort(t+1,t+k+1,cmp2);
	for(int i=1;i<=k;i++){
		for(int j=i+1;j<=k;j++){
			if(s[t[j]].y-s[t[i]].y>=d) break;
			d=min(d,dis(t[i],t[j]));
		}
	}
	return d;
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d%d",&s[i].x,&s[i].y);
	sort(s+1,s+n+1,cmp);
	printf("%.0lf",pow(mer(1,n),2));
	return 0;
}

4.P4423 BJWC2011 最小三角形

求最近的三个点。

和上面差不多,只是确定了划分线后,只保留 fabs(s[mid].x-s[i].x)<ans/2.0 的部分。

#include<bits/stdc++.h>
#define db double
using namespace std;
const int N=1e6+10;
int n;
int t[N];
struct node{int x,y;}s[N];
db ans=1e18;
db dis(int p,int q){
	int ax=s[p].x,ay=s[p].y;
	int bx=s[q].x,by=s[q].y;
	return sqrt(1.0*(ax-bx)*(ax-bx)+1.0*(ay-by)*(ay-by));
}
bool cmp(node a,node b){
	if(a.x==b.x) return a.y<b.y;
	return a.x<b.x;
}
bool cmp2(int a,int b){
	return s[a].y<s[b].y;
}
void mer(int l,int r){
	if(l==r) return;
	int mid=(l+r)>>1;
	mer(l,mid),mer(mid+1,r);
	int k=0;
	for(int i=l;i<=r;i++)
		if(fabs(s[mid].x-s[i].x)<ans/2.0) t[++k]=i;
	sort(t+1,t+k+1,cmp2);
	for(int i=1;i<=k;i++){
		for(int j=i+1;j<=k;j++){
			if(s[t[j]].y-s[t[i]].y>=ans/2.0) break;
			for(int q=j+1;q<=k;q++){
				if(s[t[q]].y-s[t[i]].y>=ans/2.0) break;
				ans=min(ans,dis(t[i],t[j])+dis(t[i],t[q])+dis(t[q],t[j]));
			}
		}
	}
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d%d",&s[i].x,&s[i].y);
	sort(s+1,s+n+1,cmp);
	mer(1,n);
	printf("%.6lf",ans);
	return 0;
}

第一节课喝了很凉的水,因为接的热水很少;第二节课长记性了,接了一杯子热水;

然后一节课没喝上水;

标签:node,int,分治,db,最近,ax,ay,平面,bx
From: https://www.cnblogs.com/Moyyer-suiy/p/17947389

相关文章

  • PostgreSQL 数据库归档最近被问及的问题问题 与 4 毋 处世学
    还是老规矩,技术加生活,先说技术,后说生活的感悟和人生的学习。在PostgreSQL中很少被提及的一个问题,归档,而这里经常有人问这个问题,所以需要写一期来说说关于ARCHIVE的问题。首先我们需要提出几个问题,1为什么要归档,PG中归档了什么2 什么时间进行归档,归档的原理与频率3  要怎么在......
  • delphi 重新打开(Reopen)或最近打开(Open Recent)列表维护
    重新打开(Reopen)或最近打开(OpenRecent)列表维护介绍列出最近打开的项目和文件,供选择重新打开。重新打开列表由一条线分为两组:项目列在线的上方(例如,MyBigApp.dproj或MyFastApp.cbproj)源文件列在线的下方(例如,MyControl.pas或MyClass.cpp)位置File>OpenRecent或Fi......
  • 三位偏序,CDQ分治入门
    (我发现我最近dp没有进展,导致我开始刷水题了。。)cdp分治,我蓝书又又看不懂了所以我还是自己去找题目做的看了看,这个应该才算是真正的入门吧这里先放上一句我觉得非常重要的话吧CDQ分治有一个重要的思想——用一个子问题来计算对另一个子问题的贡献。看到最后我对这句话的理解......
  • 【学习笔记】边分治
    算法思想和点分治类似,边分治每次选一条边,考虑跨过这条边的路径贡献,为了保证复杂度,会让两边子树大小尽量接近。发现菊花图无论怎么分治都是无效的,考虑将原树三度化,具体做法是如果\(u\)有两个儿子,就新建一个节点连接第二个儿子,如果还有更多的儿子,就再新建节点与上一次新建的节......
  • 高性能与成本效益兼备:Flomesh 服务网格 FSM 数据平面性能基准测试
    FlomeshServiceMesh(FSM)旨在提供服务网格功能、注重高性能和低资源消耗。这使得资源受限的边缘环境能够利用类似云的服务网格功能。在本次测试中,我们对FSM(v1.1.4)和Istio(v1.19.3)进行了基准测试。主要关注在使用两种不同网格时的服务延迟分布,以及数据平面的资源开销。FSM使用P......
  • git 怎么将某个开发分支最近几次的提交合并成一次提交
    1.切换到开发分支:gitcheckoutdev2.运行交互式rebase命令,并指定要合并的提交数量(在这个例子中是最近的3次提交):gitrebase-iHEAD~33.这将打开一个文本编辑器,显示要合并的提交列表。将除第一个提交外的其他提交的开头的`pick`关键字改为`squash`或`s`,保存......
  • 边分治
    namespaceBFZ{ intk=1,ssz,rt,tot; inth[N],dep[N],sz[N],vis[N]; vector<pair<int,int>>G[N]; structAB{ inta,b,c,n; }d[N*2]; voidcun(intx,inty,intz){ d[++k]={x,y,z,h[x]},h[x]=k; } voidrebuild(intx,intfa){ inttmp=0,lst=0......
  • 通达信公式怎么找最近的低点,和次低点
    Craftedby[Genie](https://marketplace.visualstudio.com/items?itemName=genieai.chatgpt-vscode)You通达信公式怎么找最近的低点,和次低点Genie在通达信公式中,要找最近的低点以及次低点,你可以使用内置的函数如LLV和REF等对价格序列进行分析。下面提供了一个示例代码,用于......
  • Python算法——最近公共祖先
    Python中的最近公共祖先(LowestCommonAncestor,LCA)算法详解最近公共祖先(LowestCommonAncestor,LCA)是二叉树中两个节点的最低共同祖先节点。在本文中,我们将深入讨论最近公共祖先问题以及如何通过递归算法来解决。我们将提供Python代码实现,并详细说明算法的原理和步骤。最近公共祖先......
  • 线段上离p最近的点 - 投影方式
    点到线段的最近距离判断依据1)投影结果<0,则线段端点a离p最近2)投影结果>线段ab的长度,则线段端点b离p最近3)否则p在线段上的垂点为最近点 p与ab不共线时1)p在线段两侧2-a)p在线段内侧2-b)p在线段内侧2 p与ab共线时1) p在线段两侧 2-a)p在线段内侧2-b......