『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年,死于圆明园.庙号世宗. 胤祯是在康乾盛世前期--康熙末年社会出现停滞的形式下登上历史舞台的.复 ...
随机推荐
- Android进阶:五、RxJava2源码解析 2
上一篇文章Android进阶:四.RxJava2 源码解析 1里我们讲到Rxjava2 从创建一个事件到事件被观察的过程原理,这篇文章我们讲Rxjava2中链式调用的原理.本文不讲用法,仍然需要读者熟 ...
- ElasticSearch本人启动报错总结
1.报错关键代码如下: Exception in thread "main" 2019-04-28 03:53:04,339 main ERROR No log4j2 config ...
- 基于TensorFlow的手写中文识别(版本一)
具体效果实现: 第一次由于设备问题所以只训练了是一些个简单的字: 第二选了23个字训练了3000在字迹清晰下能够识别: 类似于默,鼠,鼓,这类文字也能识别,由于训练数据的问题,在测试的时候应尽量写在正 ...
- ios6和ios5横竖屏切换
记录于2013/8/5 在切换横竖屏的时候调用到的一些委托方法: #pragma mark - UIApplicationDelegate //写在Appdelegate中,在具体的某一视图控制器 ...
- Ubuntu安装MySQL和Python库MySQLdb步骤
一.安装MySQL服务器和客户端 执行以下命令: sudo apt-get install mysql-server-5.6 mysql-client-5.6 sudo apt-get install ...
- Js闭包应用场合,为vue的watch加上一个延迟器
利用vue的watch可以很简单的监听数据变化 而watch来侦听数据继而调用业务逻辑是一种十分常见的模式 最典型的就是自动搜索功能,如下图,这里我们用watch侦听被双向绑定的input值,而后触发 ...
- wpf 的各个template
--转载 在使用TabControl.ListView.Menu.TreeView的时候被各种Template搞得头昏眼花,决心把这个问题搞清楚,究竟什么时候该用什么Template?这是个麻烦的问题 ...
- 一步一步 copy163: 网易严选 ---- vue-cli
面试点 组件间通信 生命周期函数 路由 - 参数 - 重定向 vuex 参考 网易严选商城小程序全栈开发,域名备案中近期上线(mpvue+koa2+mysql) 小程序服务端源码地址 小程序源码地址 ...
- Cmd命令 查看端口被占用
1)第一步 打开cmd命令窗口,输入命令:netstat -ano|findstr 输入端口号 2)第二步 继续输入命令:tasklist|findstr 第一步查询到的进程号 3)第三步 根据第二 ...
- c# 通过MailHelper发送QQ邮件
发送的方法 appsetting内容 第一个是发送邮件qq账号,第二个是QQ邮箱的POP3/SMTP服务码(下面会说怎么获取),第三个是服务器,第四个是端口 获取QQ邮箱的POP3/SMTP服务码 1 ...