博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
分治——最近点对问题 hdu1007
阅读量:4632 次
发布时间:2019-06-09

本文共 2339 字,大约阅读时间需要 7 分钟。

问题描述

n个点在公共空间中,求出所有点对的欧几里得距离最小的点对。

最近点对 

解法1: 很明显的,暴力解决是$O(N^2)$

 

解法2: 利用分治的思想,我们可以把算法优化到$O(nlogn*logn)$,甚至$O(nlogn)$

我们先对所有的点按照x坐标排序, 然后每次二分,很明显,这个二分很好写,难的是合并的操作。  即从左边A集合中选出一个点和右边集合B里面选出一个点。 

如果暴力的是去枚举左边和右边的点,还是$O(n^2)$。 

首先,我们先求出左边和右边集合的最小距离。 $d=min(dist_{left},dist_{right})$ 

 然后找出一个条左右集合的分界线。 如图所示

merge

l就是左右集合的分界线。 

我们发现,我们只要在左边集合里面枚举横坐标在[mid-d,mid]和右边集合里面横坐标在[mid,mid+d]范围内的点进行配对就可以了。 因为明显的,另外的点的距离肯定更大。  

这样就大大缩小了我们枚举的范围,但是极端情况还是很大。 

 

 

1985年Preparata和Shamos在给出该问题的一个分治算法,指出对于左边的任意一个点,右边集合和他可以匹配成为最有解的最多只有6个点。

6

如图所示: 假如左边是p点,那么在分界线的右边和p点可以配对的点不会超过6个,即在那个δ×2δ的区间里面最多只有6个点。  

 

我们用反证法来证明。  

6point

我们把δ×2δ这个矩阵按每$ \frac{2δ}{3}$来分,这样就有6个小矩形了我们可以知道每个小矩阵里面最多只有一个点,如果有两点,那么这两个点的距离一定要远一点,明显的,对角线的距离最短。 

此时对角线的距离就是$\sqrt{\frac{2δ}{3}×\frac{2δ}{3}+\frac{δ}{2}×\frac{δ}{2}}=\frac{\sqrt{5}}{6}δ$

此时说明右边原来就是小于d的点对(d和δ这里是一样的) ,明显与原来不符。 

所以最多只有6个点。(当然了,其实还能证明更少点)  

所以我们每次合并,对于左边的点最多只有6个匹配的方案。 考虑匹配方案的时候,需要对y进行排序,那么时间复杂度就变成了$O(n*logn*logn)$。  

但是其实我们可以做的更好,我们可以在分治的过程中,顺便做一个关于y坐标的归并排序,这样就不用每次对y进行sort了,时间也可以优化到$O(nlogn)$

下面是我的代码,还是写了2个$logn$的做法。 

1 #include
2 using namespace std; 3 int const N=100000+10; 4 struct node{ 5 double x,y; 6 }a[N]; 7 int cmpx(int t1,int t2){ 8 return a[t1].x
a[t2].y; 12 }13 int n,t[N],c1[N],cnt1,c2[N],cnt2; 14 double dist(int t1,int t2){15 return sqrt( (a[t1].x-a[t2].x)*(a[t1].x-a[t2].x)+(a[t1].y-a[t2].y)*(a[t1].y-a[t2].y)); 16 }17 double calc(int l,int r,int mid,double d){18 sort(c1+1,c1+cnt1+1,cmpy); 19 sort(c2+1,c2+cnt2+1,cmpy); 20 int k=1; 21 double ret=d; 22 for(int i=1;i<=cnt1;i++) {23 while (k<=cnt2 && a[c2[k]].y-a[c1[i]].y>d) k++; 24 for(int j=k;j<=cnt2;j++) 25 if( a[c1[i]].y-a[c2[j]].y
=0) c1[++cnt1]=t[i]; 43 } 44 for(int i=mid+1;i<=r;i++){45 int dd=a[t[i]].x-a[t[mid]].x; 46 if(dd
=0) c2[++cnt2]=t[i]; 47 } 48 49 return calc(l,r,mid,d);50 } 51 int main(){52 while (scanf("%d",&n)!=EOF){53 if(n==0) break; 54 for(int i=1;i<=n;i++) 55 scanf("%lf%lf",&a[i].x,&a[i].y); 56 for(int i=1;i<=n;i++) t[i]=i; 57 sort(t+1,t+n+1,cmpx); 58 printf("%0.2lf\n",close_dist(1,n)/2); 59 }60 return 0; 61 }
View Code

 

转载于:https://www.cnblogs.com/ZJXXCN/p/11117777.html

你可能感兴趣的文章
资源 | 普通程序员如何自学机器学习
查看>>
如何判断一个数是否为素数
查看>>
基本控件学习以( RadioGroup和RadioButton 的学习使用)
查看>>
Test Scenarios for Excel Export functionality
查看>>
5月3日上课笔记-XML解析
查看>>
【嵌入式开发】Raspberry Pi 树莓派性能测试
查看>>
【Qt开发】设置Qt应用程序图标
查看>>
CentOS 6.2 安装kdbg
查看>>
libevent源码分析:event_assign、event_new
查看>>
a new start in cnblogs
查看>>
luogu 2216 理想的正方形 单调队列(其实没有DP)
查看>>
在控制台应用程序下,创建窗口,避开WinMain函数入口
查看>>
最大连续子数组和--dp
查看>>
英文词频统计预备,组合数据类型练习
查看>>
缓存整个页面
查看>>
PHP范例注册审核
查看>>
jquery知识简单运用
查看>>
KMP算法练习
查看>>
git
查看>>
特殊变量的处理(一)onehot&dummy
查看>>