p1257 平面上最接近点对---(分治法)
首先就是一维最接近点的情况。。。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define INF 0x3f3f3f3f
double s[];
double ans=; int main(){
int n;
while(~scanf("%d",&n)){
for( int i=; i<n; i++ ){
scanf("%lf",s+i);
}
sort(s,s+n);
ans=INF;
for( int i=; i<n; i++ ){
ans=(s[i+]-s[i]>ans)?ans:(s[i+]-s[i]);
}
printf("%f\n",ans); }
return ;
}
很显然这是暴力求解的方法。。。
但是这种方法不适合推移到二维方面,因而推荐使用分治法进行求解没时间复杂度O(nlogn)。。。
使用分治求解:
S中的n个点为x轴上的n个实数x1,x2,...,xn。最接近点对即为这n个实数中相差最小的两个实数。显然可以先将点排好序,然后线性扫描就可以了(上述程序实现)。但我们为了便于推广到二维的情形,为下面二维,尝试用分治法解决这个问题。
假设我们用m点将S分为S1和S2两个集合,这样一来,对于所有的p(S1中的点)和q(S2中的点),有p<q。
递归地在S1和S2上找出其最接近点对{p1,p2}和{q1,q2},并设
d = min{ |p1-p2| , |q1-q2| }
由此易知,S中最接近点对或者是{p1,p2},或者是{q1,q2},或者是某个{q3,p3},如下图所示。
如果最接近点对是{q3,p3},即|p3-q3|<d,则p3和q3两者与m的距离都不超过d,且在区间(m-d,d]和(d,m+d]各有且仅有一个点。这样,就可以在线性时间内实现合并。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<ctime>
#include<algorithm>
using namespace std;
#define INF 0x3f3f3f3f
double s[];
double ans=; double closest(int low,int high){
if(low+==high) return s[high]-s[low];
if(low+==high) return min(s[low+]-s[low],s[high]-s[low+]);
int mid=(low+high)>>;
double tmp=min(closest(low,mid),closest(mid+,high));
if(s[mid+]-s[mid]<tmp) tmp=s[mid+]-s[mid];
return tmp;
} int main(){
int n,m;
srand((unsigned)time(NULL));
while(~scanf("%d",&n)){
for( int i=; i<n; i++ ){
s[i]=rand()%;
printf("%f",s[i]);
}
printf("\n");
sort(s,s+n);
for( int i=; i<n; i++ ){
printf("%f ",s[i]);
}
printf("\n");
printf("%.4f\n",closest(,n-));
}
return ;
}
接下来二为最接近点对的情况。。。
分治:
1) 把它分成两个或多个更小的问题;
2) 分别解决每个小问题;
3) 把各小问题的解答组合起来,即可得到原问题的解答。小问题通常与原问题相似,可以递归地使用分而治之策略来解决。
其实,这里 用到了分治的思想。将所给平面上n个点的集合S分成两个子集S1和S2,每个子集中约有n/2个点。然后在每个子集中递归地求最接近的点对。在这里,一个 关键的问题是如何实现分治法中的合并步骤,即由S1和S2的最接近点对,如何求得原集合S中的最接近点对。如果这两个点分别在S1和S2中,问题就变得复 杂了。
在二维的情况下:
我们仿照一维的情况先把所有点按照x(横坐标)从左到右升序排列.
以X横坐标中间的点作为分界线.将平面的点分成左边和右边,以上图为例,分为左边5个右边5个.
然后找到左边的点中最近点对的距离d1,和右边最近点对的距离d2。
令d=min{d1,d2}.那么d是当前整个平面的最近点对的距离吗?
答案不是!!
当前的d1,d2都是两边各自的点的最近距离,但是没有考虑到两边的点相互配对的情况,即是点对一个在左边区域,一个在右边区域.
如果我们这个时候把两边相互配对的所有情况全部罗列出来那么时间复杂度就变为第一种方法的O(n2).
这个时候我们便可以用上面找到的d来限制配对.即是明显超过d的两点不需要配对.如下:
那么在范围内的只有三个点,也就是说只有这个三个点相互配对的距离才可能比d小.那么再按照方法一一样在这些点中找到最短距离再跟d去比较.小的就是当前整个平面中所考虑的所有点中最近点对的距离。
然而在以上问题处理上,有一个问题尚未解决就是如何找到两边区域中的最近点对的距离d1,d2 ?
我们可以发现在处理上面这个问题的时候,和最开始处理所有平面的点最近点距离的问题类似,只是点的数目减半了.
那么我们可以递归以上问题.直到划分的区域中只有二个或者三个点.这样,该区域的最近点对距离就是对应的距离。这也是递归终止的条件。
#include<iostream>
#include<cstdio>
#include<string>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=1e4+; struct point {
double x,y;
}p[maxn];
int a[maxn]; bool cmpx(point a,point b){
return a.x<b.x;
} bool cmpy(int a,int b){
return p[a].y<p[b].y;
} double dis(point a,point b){
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
} double closest(int low,int high){
if(low+==high) return dis(p[low],p[high]);
if(low+==high) return min(dis(p[low],p[high]),min(dis(p[low],p[low+]),dis(p[low+],p[high]))); int mid=(low+high)>>;
double ans=min(closest(low,mid),closest(mid+,high)); int cnt=;
for( int i=low; i<=high; i++ ){
if(p[i].x>=p[mid].x-ans&&p[i].x<=p[mid].x+ans){
a[cnt++]=i;
}
}
sort(a,a+cnt,cmpy);
for( int i=; i<cnt; i++ ){
for( int j=i+; j<cnt; j++ ){
if(p[a[j]].y-p[a[i]].y>=ans) break;
ans=min(ans,dis(p[a[j]],p[a[i]]));
}
}
return ans;
} int main(){
int n;
while(~scanf("%d",&n)){
for( int i=; i<n; i++ ){
scanf("%lf%lf",&p[i].x,&p[i].y);
}
sort(p,p+n,cmpx); printf("%.4f\n",closest(,n-));
}
return ;
}
p1257 平面上最接近点对---(分治法)的更多相关文章
- 洛谷 P1257 平面上的最接近点对 题解
P1257 平面上的最接近点对 题目描述 给定平面上n个点,找出其中的一对点的距离,使得在这n个点的所有点对中,该距离为所有点对中最小的. 输入格式 第一行:n:2≤n≤10000 接下来n行:每行两 ...
- Luogu P1257 平面上的最接近点对_暴力
这道题数据不大 两点距离用勾股定理求 #include<iostream> #include<cmath> using namespace std; struct node{ ...
- Luogu P1257 平面上的最接近点对 暴力
这道题数据不大 两点距离用勾股定理求 #include<iostream> #include<cmath> using namespace std; struct node{ ...
- 洛谷P1257 平面上的最接近点对
n<=10000个点,求欧几里德距离最小的一对点. 经典分治,把这些点按x排序,分成两半,每边分别算答案,答案是左边的最小,右边的最小,左右组起来的最小三者的最小.发现只有左右组的有点难写. 假 ...
- P1257 平面上的最接近点对
题目描述 给定平面上n个点,找出其中的一对点的距离,使得在这n个点的所有点对中,该距离为所有点对中最小的 输入输出格式 输入格式: 第一行:n:2≤n≤200000 接下来n行:每行两个实数:x y, ...
- uva10245-The Closest Pair Problem(平面上的点分治)
解析:平面上的点分治,先递归得到左右子区间的最小值d,再处理改区间,肯定不会考虑哪些距离已经大于d的点对,对y坐标归并排序,然后从小到大开始枚举更新d,对于某个点,x轴方向只用考虑[x-d,x+d]( ...
- POJ C程序设计进阶 编程题#4:寻找平面上的极大点
编程题#4:寻找平面上的极大点 来源: POJ (Coursera声明:在POJ上完成的习题将不会计入Coursera的最后成绩.) 注意: 总时间限制: 1000ms 内存限制: 65536kB 描 ...
- COJN 0485 800503寻找平面上的极大点
800503寻找平面上的极大点 难度级别:C: 运行时间限制:1000ms: 运行空间限制:51200KB: 代码长度限制:2000000B 试题描述 在一个平面上,如果有两个点(x,y),(a,b) ...
- 平面上的地图搜索--Java学习笔记(四)
版权声明: 本文由Faye_Zuo发布于http://www.cnblogs.com/zuofeiyi/, 本文可以被全部的转载或者部分使用,但请注明出处. 这一个月以来,都在学习平面上的地图搜索,主 ...
随机推荐
- django - 总结 - ModelForm
gender = forms.ChoiceField(choices=((1, '男'), (2, '女'), (3, '其他'))) # 与sql没关系 publish = forms.Choice ...
- SpringBoot(七):SpringBoot整合Swagger2
原文地址:https://blog.csdn.net/saytime/article/details/74937664 手写Api文档的几个痛点: 文档需要更新的时候,需要再次发送一份给前端,也就是文 ...
- Lua中__index和__newindex实践
[具有默认值的table] 我们都知道,table中的任何字段的默认值都是nil,但是通过元表,我们可以很容易的修改这一规定,代码如下: function setDefault(tb, default ...
- JavaScript入门学习笔记(异常处理)
try:语句测试代码块的错误,当try中的代码块出错时执行catch中的代码块. catch:语句处理错误: throw:语句创建或抛出自定义异常. 三者一起使用可以控制程序流并生成自定义异常信息. ...
- sqlalchemy的使用
from sqlalchemy import Column, Integer, String, Text, ForeignKey, DateTime, UniqueConstraint, Index ...
- 学习笔记: MD5/DES/RSA三类加密,SSL协议解析
1. 不对称可逆加密的 的2种用法 (1)保证信息不被篡改 (2) 保证信息只能被我看到 2. CA证书的基本原理 流程如下: 百度公司 向CA机构报备 持有者姓名, 有效期, 要发布的公钥 , 扩 ...
- Elasticsearch 简单快照备份
创建仓库 POST http://10.10.14.201:9200/_snapshot/backup { "type": "fs", "settin ...
- 【JAVA】servlet 定时启动
步骤一: web.xml中加上如下的代码: <load-on-startup>10</load-on-startup>这句话是重点. <servlet> <s ...
- SQL反模式学习笔记11 限定列的有效值
目标:限定列的有效值,将一列的有效字段值约束在一个固定的集合中.类似于数据字典. 反模式:在列定义上指定可选值 1. 对某一列定义一个检查约束项,这个约束不允许往列中插入或者更新任何会导致约束失败的值 ...
- IntelliJ IDEA 中 Web项目 目录结构
--src 应用程序源代码和测试程序代码的根目录 --main --java 应用程序源代码目录 --resources 应用程序用到的资源文件(一般都是配置文件) --webapp web项 ...