<更新提示>

<第一次更新>


<正文>

平面最近点对

平面最近点对算是一个经典的问题了,虽然谈不上是什么专门的算法,但是拿出问题模型好好分析一个是有必要的。

给定\(n\)个二元组\((x,y)\),代表同一平面内的\(n\)个点的坐标,求\(\min\{dis_{(p,q)}\}\)。

其中,定义\(dis_{(p,q)}\)代表两点的直线距离,即\(dis_{(p,q)}=\sqrt{(p_x-q_x)^2+(p_y-q_y)^2}\)。

\(Solution\ 1:\)

暴力求解,\(O(n^2)\)枚举两点,直接计算更新答案。

\(Solution\ 2:\)

分治,先将所有点以横坐标为第一关键字,纵坐标为第二关键字排序。

定义一个问题\(divide(l,r)\)代表排序后点\(l\)到点\(r\)这一段的最优解。然后,对于每一个问题,我们取一个中间点\(mid=(l+r)/2\),那么这个问题的解可以分三种情况讨论:

\(1.\)最优的点对在点\(mid\)左侧(包括\(mid\))

\(2.\)最优的点对在点\(mid\)右侧

\(3.\)最优的点对一个在\(mid\)左侧(包括\(mid\)),一个在\(mid\)右侧

显然,对于\(1.2.\)两种情况,我们可以直接通过递归调用子问题\(divide(l,mid)\)和\(divide(mid+1,r)\)来求解,那么我们最大的问题就是解决第三种情况。

试想,如果我们暴力枚举两边的点,那么时间复杂度仍为\(O(n^2)\),分治就失去了意义。考虑一个优化,假设我们已经得到子问题的答案\(d=\min\{divide(l,mid),divide(mid+1,r)\}\),那么任何一个横坐标距\(mid\)大于\(d\)的点都不可能成为更优的解

那么我们开一个临时数组,将所有横坐标距\(mid\)小于等于\(d\)的点加入这个数组中,然后到这个数字中枚举找到最优解。

考虑再优化一下,设上一步操作得到的点集为\(S\),那么我们还可以将\(S\)按纵坐标排序,如果更新最优解时发现两点纵坐标之差大于\(d\),可以直接退出循环,达到优化的效果。

事实上,可以证明,只枚举横纵坐标与\(mid\)之差小于\(d\)的点,这样的点至多只有\(6\)个,对时间复杂度的贡献是常数级别的,那么分治的时间复杂度就是递归的时间复杂度加上每次扫描加入备选答案点集的时间复杂度,很容易计算得出时间复杂度为\(O(nlog_2n)\)。

关于上文提到点集大小小于等于\(6\)的详细证明,可以看这个博客

Raid(POJ3714)

Description

在与联盟的战斗中连续失败后,帝国撤退到最后一个据点。 根据其强大的防御系统,帝国击退了联盟攻击的六波浪潮。 经过几个不眠之夜,联盟将军亚瑟注意到,防御系统唯一的弱点就是能源供应。 该系统由N个核电站充电,其中任何一个都会使系统失效。

这位将军很快就开始对N个特工人员进行突袭,这些特工人员进入了据点。 不幸的是,由于帝国空军的袭击,他们未能降落在预期位置。 作为一名经验丰富的将军,亚瑟很快意识到他需要重新安排计划。 他现在想知道的第一件事就是哪个代理商离任何一个发电站最近。 你是否可以帮助将军计算代理人和车站之间的最小距离?

Input Format

第一行是表示测试用例数的整数T. 每个测试用例以整数N开头。 (1 ≤≤ N ≤≤ 100000). 接下来的N行描述了站点的位置。 每行包括两个整数X(0 ≤≤ X ≤≤ 1000000000)和Y(0 ≤≤ Y ≤≤ 1000000000),表示该站的位置。 接下来的N行描述了代理的位置。 每行包含两个整数X(0 ≤≤ X ≤≤ 1000000000)和Y(0 ≤≤ Y ≤≤ 1000000000),表示代理的位置。

Output Format

对于每个测试用例输出,最小距离精度为三位小数放在一个单独的行中。

Sample Input

2
4
0 0
0 1
1 0
1 1
2 2
2 3
3 2
3 3
4
0 0
0 0
0 0
0 0
0 0
0 0
0 0
0 0

Sample Output

1.414
0.000

解析

这道就是平面最近点对模板题嘛。给定\(2n\)个点,求第一个点集中的点到第二个点集中的点的最短距离。对于不同的点集的点,我们直接定义距离为正无穷,然后分治就可以了。

\(Code:\)

#include<bits/stdc++.h>
using namespace std;
#define mset(name,val) memset(name,val,sizeof name)
#define filein(str) freopen(str".in","r",stdin)
#define fileout(str) freopen(str".out","w",stdout)
const int N=100000+20;
const double INF=1e30,eps=1e-5;
int n;
struct node{double x,y;bool flag;}vertex[2*N];
inline void input(void)
{
scanf("%d",&n);
for(int i=1;i<=2*n;i++)
{
scanf("%lf%lf",&vertex[i].x,&vertex[i].y);
if(i<=n)vertex[i].flag=0;
else vertex[i].flag=1;
}
}
inline double dis(node a,node b)
{
if(a.flag==b.flag)return INF;
return sqrt( ( (a.x-b.x) * (a.x-b.x) * 1.0 ) * 1.0 + ( (a.y-b.y) * (a.y-b.y) * 1.0 ) * 1.0 );
}
inline bool comparex(node a,node b)
{
return a.x<b.x;
}
inline bool comparey(node a,node b)
{
return a.y<b.y;
}
inline double divide(int l,int r)
{
if(l==r)return INF;
if(r-l==1)return dis(vertex[l],vertex[r]);
int mid=(l+r)/2;
vector < node > t;t.clear();
double res=min(divide(l,mid),divide(mid+1,r));
for(int i=l;i<=r;i++)
if( fabs( vertex[i].x - vertex[mid].x ) <= res )
t.push_back(vertex[i]);
sort(t.begin(),t.end(),comparey);
for(int i=0;i<t.size()-1;i++)
{
for(int j=i+1;j<t.size();j++)
{
if(t[j].y-t[i].y>res)break;
res=min(res,dis(t[i],t[j]));
}
}
return res;
}
int main(void)
{
int T;
scanf("%d",&T);
while(T--)
{
input();
sort(vertex+1,vertex+2*n+1,comparex);
printf("%.3lf\n",divide(1,2*n));
}
return 0;
}

<后记>

『Raid 平面最近点对』的更多相关文章

  1. POJ-3714 Raid 平面最近点对

    题目链接:http://poj.org/problem?id=3714 分治算法修改该为两个点集的情况就可以了,加一个标记... //STATUS:C++_AC_2094MS_4880KB #incl ...

  2. 【POJ3714】Raid:平面最近点对

    Description After successive failures in the battles against the Union, the Empire retreated to its ...

  3. poj3714 Raid(分治求平面最近点对)

    题目链接:https://vjudge.net/problem/POJ-3714 题意:给定两个点集,求最短距离. 思路:在平面最近点对基础上加了个条件,我么不访用f做标记,集合1的f为1,集合2的f ...

  4. POJ 3741 Raid (平面最近点对)

    $ POJ~3741~Raid $ (平面最近点对) $ solution: $ 有两种点,现在求最近的平面点对.这是一道分治板子,但是当时还是想了很久,明明知道有最近平面点对,但还是觉得有点不对劲. ...

  5. $Poj3714/AcWing\ Raid$ 分治/平面最近点对

    $AcWing$ $Sol$ 平面最近点对板子题,注意要求的是两种不同的点之间的距离. $Code$ #include<bits/stdc++.h> #define il inline # ...

  6. 计算几何 平面最近点对 nlogn分治算法 求平面中距离最近的两点

    平面最近点对,即平面中距离最近的两点 分治算法: int SOLVE(int left,int right)//求解点集中区间[left,right]中的最近点对 { double ans; //an ...

  7. HDU-4631 Sad Love Story 平面最近点对

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4631 数据是随机的,没有极端数据,所以可以分段考虑,最小值是一个单调不增的函数,然后每次分治算平面最近 ...

  8. HDU1007--Quoit Design(平面最近点对)

    Problem Description Have you ever played quoit in a playground? Quoit is a game in which flat rings ...

  9. Vijos 1012 清帝之惑之雍正 平面最近点对(分治)

    背景 雍正帝胤祯,生于康熙十七年(1678)是康熙的第四子.康熙61年,45岁的胤祯继承帝位,在位13年,死于圆明园.庙号世宗. 胤祯是在康乾盛世前期--康熙末年社会出现停滞的形式下登上历史舞台的.复 ...

随机推荐

  1. flink连接hbase方法及遇到的问题

    1.继承 RichSinkFunction 类 mvn配置: <dependency> <groupId>org.apache.flink</groupId> &l ...

  2. pygame学习之绘制移动的矩形

    import pygame from pygame.locals import * pygame.init() screen = pygame.display.set_mode((600, 500)) ...

  3. HDU 2243考研路茫茫——单词情结 (AC自动机+矩阵快速幂)

    背单词,始终是复习英语的重要环节.在荒废了3年大学生涯后,Lele也终于要开始背单词了. 一天,Lele在某本单词书上看到了一个根据词根来背单词的方法.比如"ab",放在单词前一般 ...

  4. [Git]2018-10 解决git cmd中文乱码问题

    2018年10月12日 莫名其妙出现cmd下git log中文乱码问题,显示一堆<E4><A8>之类的乱码.git bash却一切正常. 怀疑是Windows系统升级出现的不兼 ...

  5. C# 中传参中的OUT 和 ref 区别 笔记

    //out传参前需要对参数进行赋值处理,ref则不需要.//out.ref 传参都可以对值进行改变 1 static void Main(string[] args) { ; //int J = 10 ...

  6. Flume+Kafka+Storm整合

    Flume+Kafka+Storm整合 1. 需求: 有一个客户端Client可以产生日志信息,我们需要通过Flume获取日志信息,再把该日志信息放入到Kafka的一个Topic:flume-to-k ...

  7. Scanner,Random,匿名对象-------------------java基础学习第七天

    1.API 2.Scanner 功能:通过键盘输入数据到程序中. 引用类型的一般使用步骤: 导包 Import 包路径.类名称 只有java.lang 包写的类不需要导包,其他都需要 2.创建 类名称 ...

  8. hy这个破项目

    最近部署hy记事 这段时间摊上了个挺恶心的项目,叫什么hy鞋同平台..前后左右整的人挺难受的.学到的东西特别少,而且比较浪费时间.不过,还是总结一下吧,好歹花了这么久的时间了 Doc管理xi tong ...

  9. 批量引用iconfont字体图标到项目

    打开https://www.iconfont.cn/网址登录后选择你需要的图标添加到购物车中 点击下载代码或者添加到项目后再下载代码,再找到之前下载的的文件,拷贝到项目中

  10. Linux jdk 环境变量配置

    备忘,引用自:http://blog.csdn.net/lzwglory/article/details/54233248 1. 永久修改,对所有用户有效  # vi /etc/profile //按 ...