热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

【题解】袭击

题目链接题目描述在与联盟的战斗中屡战屡败后,帝国撤退到了最后一个据点。依靠其强大的防御系统,帝国击退了联盟的六波猛烈进攻。经过几天的苦思冥想,联盟将军亚瑟终于注意到帝国防御系

题目链接


题目描述


在与联盟的战斗中屡战屡败后,帝国撤退到了最后一个据点。

依靠其强大的防御系统,帝国击退了联盟的六波猛烈进攻。

经过几天的苦思冥想,联盟将军亚瑟终于注意到帝国防御系统唯一的弱点就是能源供应。

该系统由 \(N\) 个核电站供应能源,其中任何一个被摧毁都会使防御系统失效。

将军派出了 \(N\) 个特工进入据点之中,打算对能源站展开一次突袭。

不幸的是,由于受到了帝国空军的袭击,他们未能降落在预期位置。

作为一名经验丰富的将军,亚瑟很快意识到他需要重新安排突袭计划。

他现在最想知道的事情就是哪个特工距离其中任意一个发电站的距离最短。

你能帮他算出来这最短的距离是多少吗?



输入格式


输入中包含多组测试用例。

第一行输入整数 \(T\) ,代表测试用例的数量。

对于每个测试用例,第一行输入整数 \(N\)

接下来N行,每行输入两个整数 \(X\)\(Y\),代表每个核电站的位置的 \(X\)\(Y\) 坐标。

在接下来N行,每行输入两个整数X和Y,代表每名特工的位置的X,Y坐标。



输出格式


每个测试用例,输出一个最短距离值,结果保留三位小数。

每个输出结果占一行。



样例


样例输入

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

样例输出

1.414
0.000

数据范围与提示

\(1\le N\le100000\)

\(0\le X,Y\le1000000000\)


Solution

分治。(不要问我怎么知道的)

铺垫 题解

好了,等你看完上面的部分,这题最妙的部分就不用我讲了,我就没事干了,本文终结。

对于同一个分组,它的最近点对我们可以这样求解:

将它按 \(x\) 优先, \(y\) 其次的规则从小到大排序,凡是看到关于坐标的不简单题,是个人都会先把 \(\operatorname{sort}\) 写上。可惜我不是人

那么,现在这个数组已经从左到右排好了,我们把它分成两半截。开始盗图

假设我们已经求出来了 \([left,mid]\) 的答案和 \([mid+1,right]\) 的答案,我们用 \(d\) (也就是记录答案的变量)记录它们的 \(\min\) 值。

但四!可爱的孩纸们,难道距离最近的就不可能在中间那一段吗?

在上图中:



  • 蓝色+紫色为答案可能区间1( \([left,mid]\) )

  • 紫色+橙色为答案可能区间2( 将求的值 )

  • 橙色+绿色为答案可能区间3( \([mid+1,right]\) )

那么,区间2如何处理呢?

上图中,紫色和橙色长方形的宽都是 \(d\),为什么呢?因为只有当它们的距离在 \(d\) 范围内, \(d\) 才有可能被更新,所以我们只用计算 \(l\) ~ \(r\) 中,\(x\) 坐标在 \([mid-d,mid+d]\) 范围内的点就行啦!

把满足上述要求的点放在 \(tmp\) 数组中,由于这个数组本身已经在范围内了,此时我们按 \(y\) 坐标排序,这样便于找到与某个点距离最近的点。

枚举 \(tmp\) 中的每一对点。当这一对点的 \(y\) 坐标的距离大于 \(d\) 时,我们就可以 \(break\) 掉了。因为已经按 \(y\) 坐标排好序, \(y\) 小的点太远,更大的自然不行。

但,这只是同一个分组的情况。不同分组其实也没有什么不同,就是在求距离的时候判一下就行了。

综上所述。。。


Code

#include
#include
#include
#include
using std::sort;
typedef double db;
const int maxn=1e5+5;
const db inf=DBL_MAX;
struct node{
db x,y;
bool type;
db operator-(const node q)const{
if(type==q.type)return inf;
return sqrt((x-q.x)*(x-q.x)+(y-q.y)*(y-q.y));
}
}a[maxn],tmp[maxn];
int T,n;
bool cmpx(node x,node y){
return x.x==y.x?x.y}
bool cmpy(node x,node y){
return x.y==y.y&&x.x}
db min(db x,db y){
return x}
db max(db x,db y){
return x>y?x:y;
}
db ll45l4(int l,int r){ //恶臭函数名
if(r-l<=1)return a[r]-a[l];
int mid=l+r>>1,cnt=0;
db d=min(ll45l4(l,mid),ll45l4(mid+1,r));
for(int i=l;i<=r;++i){
if(a[mid].x-d<=a[i].x&&a[mid].x+d>=a[i].x)
tmp[++cnt]=a[i];
}
sort(tmp+1,tmp+cnt+1,cmpy);
for(int i=1;i<=cnt;++i){
for(int j=i+1;j<=cnt;++j){
if(a[j].y-a[i].y>d)break;
d=min(d,a[i]-a[j]);
}
}
return d;
}
int main(){
scanf("%d",&T);
while(T--){
scanf("%d",&n);
for(int i=1;i<=n;++i){
scanf("%lf%lf",&a[i].x,&a[i].y);
a[i].type=0;
}
for(int i=1;i<=n;++i){
scanf("%lf%lf",&a[n+i].x,&a[n+i].y);
a[i].type=1;
}
n<<=1;
sort(a+1,a+n+1,cmpx);
printf("%.3lf\n",ll45l4(1,n));
}
return 0;
}

end.

—— · EOF · ——

千里之行,始于足下



推荐阅读
  • 本文介绍了一种图的存储和遍历方法——链式前向星法,该方法在存储带边权的图时时间效率比vector略高且节省空间。然而,链式前向星法存图的最大问题是对一个点的出边进行排序去重不容易,但在平行边无所谓的情况下选择这个方法是非常明智的。文章还提及了图中搜索树的父子关系一般不是很重要,同时给出了相应的代码示例。 ... [详细]
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • 本文介绍了P1651题目的描述和要求,以及计算能搭建的塔的最大高度的方法。通过动态规划和状压技术,将问题转化为求解差值的问题,并定义了相应的状态。最终得出了计算最大高度的解法。 ... [详细]
  • 动态规划算法的基本步骤及最长递增子序列问题详解
    本文详细介绍了动态规划算法的基本步骤,包括划分阶段、选择状态、决策和状态转移方程,并以最长递增子序列问题为例进行了详细解析。动态规划算法的有效性依赖于问题本身所具有的最优子结构性质和子问题重叠性质。通过将子问题的解保存在一个表中,在以后尽可能多地利用这些子问题的解,从而提高算法的效率。 ... [详细]
  • 本文介绍了指针的概念以及在函数调用时使用指针作为参数的情况。指针存放的是变量的地址,通过指针可以修改指针所指的变量的值。然而,如果想要修改指针的指向,就需要使用指针的引用。文章还通过一个简单的示例代码解释了指针的引用的使用方法,并思考了在修改指针的指向后,取指针的输出结果。 ... [详细]
  • C++中的三角函数计算及其应用
    本文介绍了C++中的三角函数的计算方法和应用,包括计算余弦、正弦、正切值以及反三角函数求对应的弧度制角度的示例代码。代码中使用了C++的数学库和命名空间,通过赋值和输出语句实现了三角函数的计算和结果显示。通过学习本文,读者可以了解到C++中三角函数的基本用法和应用场景。 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • Go语言实现堆排序的详细教程
    本文主要介绍了Go语言实现堆排序的详细教程,包括大根堆的定义和完全二叉树的概念。通过图解和算法描述,详细介绍了堆排序的实现过程。堆排序是一种效率很高的排序算法,时间复杂度为O(nlgn)。阅读本文大约需要15分钟。 ... [详细]
  • 本文介绍了深入浅出Linux设备驱动编程的重要性,以及两种加载和删除Linux内核模块的方法。通过一个内核模块的例子,展示了模块的编译和加载过程,并讨论了模块对内核大小的控制。深入理解Linux设备驱动编程对于开发者来说非常重要。 ... [详细]
  • JDK源码学习之HashTable(附带面试题)的学习笔记
    本文介绍了JDK源码学习之HashTable(附带面试题)的学习笔记,包括HashTable的定义、数据类型、与HashMap的关系和区别。文章提供了干货,并附带了其他相关主题的学习笔记。 ... [详细]
  • 海马s5近光灯能否直接更换为H7?
    本文主要介绍了海马s5车型的近光灯是否可以直接更换为H7灯泡,并提供了完整的教程下载地址。此外,还详细讲解了DSP功能函数中的数据拷贝、数据填充和浮点数转换为定点数的相关内容。 ... [详细]
  • 实现一个通讯录系统,可添加、删除、修改、查找、显示、清空、排序通讯录信息
    本文介绍了如何实现一个通讯录系统,该系统可以实现添加、删除、修改、查找、显示、清空、排序通讯录信息的功能。通过定义结构体LINK和PEOPLE来存储通讯录信息,使用相关函数来实现各项功能。详细介绍了每个功能的实现方法。 ... [详细]
  • Java编程实现邻接矩阵表示稠密图的方法及实现类介绍
    本文介绍了Java编程如何实现邻接矩阵表示稠密图的方法,通过一个名为AMWGraph.java的类来构造邻接矩阵表示的图,并提供了插入结点、插入边、获取邻接结点等功能。通过使用二维数组来表示结点之间的关系,并通过元素的值来表示权值的大小,实现了稠密图的表示和操作。对于对稠密图的表示和操作感兴趣的读者可以参考本文。 ... [详细]
  • 本文介绍了一道经典的状态压缩题目——关灯问题2,并提供了解决该问题的算法思路。通过使用二进制表示灯的状态,并枚举所有可能的状态,可以求解出最少按按钮的次数,从而将所有灯关掉。本文还对状压和位运算进行了解释,并指出了该方法的适用性和局限性。 ... [详细]
  • 深入理解Java虚拟机的并发编程与性能优化
    本文主要介绍了Java内存模型与线程的相关概念,探讨了并发编程在服务端应用中的重要性。同时,介绍了Java语言和虚拟机提供的工具,帮助开发人员处理并发方面的问题,提高程序的并发能力和性能优化。文章指出,充分利用计算机处理器的能力和协调线程之间的并发操作是提高服务端程序性能的关键。 ... [详细]
author-avatar
Lo海豚
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有