<更新提示>

<第一次更新>


<正文>

平面最近点对

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

给定\(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. 什么是nrm

    什么是nrm nrm 是一个 npm 源管理器,允许你快速地在 npm 源间切换. 安装nrm 在命令行执行命令,npm install -g nrm,全局安装nrm. 使用 执行命令nrm ls查看 ...

  2. centos7基于samba服务配置实例

    需求: 账号建立:产研部门所有人员,产品.开发.测试.运维: 目录建立:各二级部门分别建立以部门名称为文件夹的目录: 初步权限管理:各部门成员对本部门目录有读写权限,对其他部门目录有读权限: 建立共享 ...

  3. tensorflow 使用 2 Felch ,Feed

    Felch ::在会话里可以执行多个 op , import tensorflow as tf input1 = tf.constant(3.0) input2 = tf.constant(2.0) ...

  4. Cocos2d-js和Android交互

    说白了,就是JavaScript和Java之间的函数互相调用. 先看一下效果 有了这个交互,为了以后接sdk做准备. 要点: javascript调用java: jsb.reflection.call ...

  5. tf.contrib.slim.data数据加载(1) reader

    reader: 适用于原始数据数据形式的Tensorflow Reader 在库中parallel_reader.py是与reader相关的,它使用多个reader并行处理来提高速度,但文件中定义的类 ...

  6. 锐捷交换机配置DHCP SERVER给固定的MAC地址分配静态IP

    今天突发奇想,想给自己的手机分配固定地址,使得接入公司无线网络时每次都取到同一ip地址,这样可以排除认证登录问题. 上网溜达一下,记录下锐捷官方的[常见问题]如下,经验证可行. 需求: 给MAC地址为 ...

  7. Kafka监控工具kafka-monitor v0.1简要介绍

    Kafka Monitor为Kafka的可视化管理与监控工具,为Kafka的稳定运维提供高效.可靠.稳定的保障,这里主要简单介绍Kafka Monitor的相关功能与页面的介绍: Kafka Moni ...

  8. IOS开发中将定时器添加到runLoop中

    runLoop主要就是为线程而生的.他能够让线程在有任务的时候保持工作状态,没有任务的时候让线程处于休眠待备状态. 主线程的runloop默认是开启的.主线程上创建的定时器已经默认添加到runLoop ...

  9. Android第一次作业

    Android第一次作业——天气预报界面 成果图: 思路: 运用RelativeLayout布局管理器来设计整体布局,在其中插入需要的图片和文本框,并设置其字体格式和背景.最后用HorizontalS ...

  10. [AtCoder3856]Ice Rink Game - 模拟

    Problem Statement An adult game master and N children are playing a game on an ice rink. The game co ...