『Raid 平面最近点对』
<更新提示>
<第一次更新>
<正文>
平面最近点对
平面最近点对算是一个经典的问题了,虽然谈不上是什么专门的算法,但是拿出问题模型好好分析一个是有必要的。
给定\(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 平面最近点对』的更多相关文章
- POJ-3714 Raid 平面最近点对
题目链接:http://poj.org/problem?id=3714 分治算法修改该为两个点集的情况就可以了,加一个标记... //STATUS:C++_AC_2094MS_4880KB #incl ...
- 【POJ3714】Raid:平面最近点对
Description After successive failures in the battles against the Union, the Empire retreated to its ...
- poj3714 Raid(分治求平面最近点对)
题目链接:https://vjudge.net/problem/POJ-3714 题意:给定两个点集,求最短距离. 思路:在平面最近点对基础上加了个条件,我么不访用f做标记,集合1的f为1,集合2的f ...
- POJ 3741 Raid (平面最近点对)
$ POJ~3741~Raid $ (平面最近点对) $ solution: $ 有两种点,现在求最近的平面点对.这是一道分治板子,但是当时还是想了很久,明明知道有最近平面点对,但还是觉得有点不对劲. ...
- $Poj3714/AcWing\ Raid$ 分治/平面最近点对
$AcWing$ $Sol$ 平面最近点对板子题,注意要求的是两种不同的点之间的距离. $Code$ #include<bits/stdc++.h> #define il inline # ...
- 计算几何 平面最近点对 nlogn分治算法 求平面中距离最近的两点
平面最近点对,即平面中距离最近的两点 分治算法: int SOLVE(int left,int right)//求解点集中区间[left,right]中的最近点对 { double ans; //an ...
- HDU-4631 Sad Love Story 平面最近点对
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4631 数据是随机的,没有极端数据,所以可以分段考虑,最小值是一个单调不增的函数,然后每次分治算平面最近 ...
- HDU1007--Quoit Design(平面最近点对)
Problem Description Have you ever played quoit in a playground? Quoit is a game in which flat rings ...
- Vijos 1012 清帝之惑之雍正 平面最近点对(分治)
背景 雍正帝胤祯,生于康熙十七年(1678)是康熙的第四子.康熙61年,45岁的胤祯继承帝位,在位13年,死于圆明园.庙号世宗. 胤祯是在康乾盛世前期--康熙末年社会出现停滞的形式下登上历史舞台的.复 ...
随机推荐
- python基础day1
一.python介绍 1.1简介 Python (英国发音:/ˈpaɪθən/ 美国发音:/ˈpaɪθɑːn/), 是一种面向对象的解释型计算机程序设计语言,由荷兰人Guido van Rossum ...
- 在WINDOWS中安装使用GSL(MinGW64+Sublime Text3 & Visual Studio)
本文介绍在Windows下安装使用GSL库,涉及GSL两个版本(官方最新版及GSL1.8 VC版).msys shell.GCC.G++等内容,最终实现对GSL安装及示例基于MinGW64在Subli ...
- java位移运算符 转
https://blog.csdn.net/qq_36134429/article/details/78286416#commentsedit java移位运算符不外乎就这三种:<<(左移 ...
- 二、OpenStack—keystone组件介绍与安装
一.Keystone介绍 keystone 是OpenStack的组件之一,用于为OpenStack家族中的其它组件成员提供统一的认证服务,包括身份验证.令牌的发放和校验.服务列表.用户权限的定义等等 ...
- C#WebApi 接口参数不再困惑:传参详解
前言:还记得刚使用WebApi那会儿,被它的传参机制折腾了好久,查阅了半天资料.如今,使用WebApi也有段时间了,今天就记录下API接口传参的一些方式方法,算是一个笔记,也希望能帮初学者少走弯路.本 ...
- Shell脚本学习 - 流程控制和函数
继续Shell的学习.上两篇是关于基本数据类型,基本语法以及运算符相关,这一篇是流程控制相关(if, for, while) 流程控制 if else 流程控制不可为空,如果else没有语句执行,就不 ...
- C++入门笔记(一)零碎基础知识
零碎基础知识 一.创建和运行程序 1.使用文本编辑器编写程序,保存为文件,该文件就叫源代码. 2.编译源代码:运行一个程序,将源代码翻译为主机使用的内部语言----机器语言.包含了 编译后程序的文件就 ...
- Hive管理表,外部表及外部分区表的深入探讨
Hive管理表,也叫内部表.Hive控制着管理表的整个生命周期,默认情况下Hive管理表的数据存放在hive的主目录:/user/hive/warehouse/下,并且当我们删除一张表时,这张表的数据 ...
- js数据类型以及数组字符串常用方法
JS判断数据类型 例子: var a = "iamstring."; var b = 222; var c= [1,2,3]; var d = new Date(); var e ...
- 查找更改的PeopleCode
当我们做工程包迁移时,经过会遗漏部分更改过的定义.我们可以用下面的SQL来查找变更项 变量 &OPRID =代码变更者 变量 &PROJECT 项目工程名 SELECT * FROM ...