题目:



Raid
Time Limit: 5000MS   Memory Limit: 65536K
Total Submissions: 7355   Accepted: 2185

Description

After successive failures in the battles against the Union, the Empire retreated to its last stronghold. Depending on its powerful defense system, the Empire repelled the six waves of Union's attack. After several sleepless nights of thinking, Arthur, General
of the Union, noticed that the only weakness of the defense system was its energy supply. The system was charged by N nuclear power stations and breaking down any of them would disable the system.

The general soon started a raid to the stations by N special agents who were paradroped into the stronghold. Unfortunately they failed to land at the expected positions due to the attack by the Empire Air Force. As an experienced general, Arthur
soon realized that he needed to rearrange the plan. The first thing he wants to know now is that which agent is the nearest to any power station. Could you, the chief officer, help the general to calculate the minimum distance between an agent and a station?

Input

The first line is a integer T representing the number of test cases.

Each test case begins with an integer N (1 ≤ N ≤ 100000).

The next N lines describe the positions of the stations. Each line consists of two integers X (0 ≤ X ≤ 1000000000) and Y (0 ≤ Y ≤ 1000000000) indicating the positions of the station.

The next following N lines describe the positions of the agents. Each line consists of two integers X (0 ≤ X ≤ 1000000000) and Y (0 ≤ Y ≤ 1000000000) indicating the positions of the agent.  

Output

For each test case output the minimum distance with precision of three decimal placed in a separate line.

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

Source

[Submit]   [Go Back]   [Status]  
[Discuss]

题意:


给一个点集A,一个点集B,求min(distance(x, y))(x∈A,y∈B)

思路分析说明也是看了别人的博客才知道的,整整搞了一天像这样的题目应该去年就会了,整整落后一年多啊具体的分析 贴在了代码中,这里就不写思路了。

算法:


分治法+剪枝优化

算法分析课上老师虽然讲过什么事分治法,但是还是没有理解,毕竟上课时都比较水,然后也没怎么上心,具体思想的掌握都不靠谱,更别提用代码实现解决问题了,而且课内的很多算法代码都是不能直接用在 acm 中的了


分治法:


划分问题:把问题的实例划分成子问题
递归求解:递归解决子问题
合并问题:合并子问题的解得到 原来的解【最难部分】

划分问题:一般是将序列划分为两个尽量相等的两半了
具体实现可以自己百度下:最大连续和问题【lrj 白书 P141页】

代码:


暴力+剪枝优化

/****************************************************************
D Accepted 4892 KB 1391 ms C++ 1222 B 2013-07-24 10:23:05
算法:暴力 + 剪枝
题意:给一个点集A,一个点集B,
求min(distance(x, y))(x∈A,y∈B)
思路:把两个集合中的点弄在一个数组中排序(分开暴力会TLE)
排序方法:x 坐标从左到右, y坐标从下到上
排序前:先找出 A 中任意一点p1和 B 中任意一点 p2的距离,记为 mini 【那么最后求出的结果不会比 mini 大。。了解!】
排序后:暴力枚举每两点的距离,不断更新 mini
剪枝优化:p[j].x-p[i].x >= mini,则 break
因为如果是这种情况,那么加上 y 坐标上的就一定会 > mini
直接跳出这一点,遍历下一点即可。
**********************************************************************/
#include<stdio.h>
#include<math.h>
#include<algorithm>
using namespace std; const int maxn = 100000+10;
const double INF = 1000000000*2; int n,N;
struct Point{
double x,y;
int flag;
}p[maxn*2]; bool cmp(Point a, Point b)
{
if(a.x == b.x) return a.y <= b.y;
else return a.x < b.x;
}
double dist(Point a, Point b)
{
return sqrt((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y));
} double minDist()
{
double mini = dist(p[0], p[n]); //排序前,找出 A 集合和 B 集合任意一点间距离 sort(p,p+N,cmp); //排序 for(int i = 0; i < N-1; i++)
{
for(int j = i+1; j < N; j++)
{
if(p[i].flag == p[j].flag) continue; //属于同一集合
if(p[j].x-p[i].x >= mini) break; // x 轴的距离就已经不小于当前最优解了,直接跳出第二层循环找下一点 double tmp = dist(p[i],p[j]); //求距离,并且更新
mini = min(mini, tmp);
}
}
return mini;
} int main()
{
int T;
scanf("%d", &T);
while(T--)
{
scanf("%d", &n);
N = 2*n;
for(int i = 0; i < n; i++)
{
scanf("%lf%lf", &p[i].x, &p[i].y);
p[i].flag = 1;
}
for(int i = n; i < N; i++)
{
scanf("%lf%lf", &p[i].x, &p[i].y);
p[i].flag = 0;
}
double ans = minDist();
printf("%.3lf\n", ans);
}
return 0;
}

分治法+剪枝优化

/****************************************************************
D Accepted 4896 KB 1704 ms C++ 1678 B 2013-07-24 15:47:05
算法:分治法 + 剪枝
题意:给一个点集A,一个点集B,
求min(distance(x, y))(x∈A,y∈B)
思路:把两个集合中的点弄在一个数组中排序
排序方法:x 坐标从左到右, y坐标从下到上(PS: y左边也可以不排序) 剪枝优化:p[j].x-p[i].x >= mini,则 break
因为如果是这种情况,那么加上 y 坐标上的就一定会 > mini
直接跳出这一点,遍历下一点即可。
分治法:先把问题分解成左右两个子问题递归求解,然后再合并即可【一般是分成相等的两半效率最高了】
对于此问题:
先分成:从左边到中间 和 从中间到右边这两个子问题求出一个可能的最小距离
然后再合并:从左边(左边到中间的那段)取出一个点 u,
从右边取出一个点 v
找出最小的dist(u,v)与前面的子问题中求出的最小距离比较即可
**********************************************************************/
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<algorithm>
using namespace std; const int maxn = 100000+10;
const double INF = 1000000000*2; struct Point{
double x,y;
int flag;
}p[2*maxn];
int index[2*maxn]; bool cmp(Point a, Point b)
{
return a.x < b.x;
} double dist(Point a, Point b)
{
if(a.flag != b.flag)
return sqrt((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y));
else return INF; /** 两点属于同一集合 */
} double min_dist(int left, int right) /**[left, right) 左闭右开区间 */
{
if(right - left == 1) return INF; /** one point 只有一个点 */
if(right - left == 2) return dist(p[right],p[right+1]); /** two point 正好两个点 */ int mid = left+(right-left)/2; /** 分治法第一步:划分成[left, mid)和[mid, right) */ double Min = min(min_dist(left, mid), min_dist(mid, right)); /** 分治法第二步:递归求解 */ int L = 0; /**记录每次合并找的点数*/
/**向左向右分别找时记得剪枝优化否则还是会 TLE **/
for(int i = mid-1; i >= left && p[mid-1].x-p[i].x < Min; i--)
{ /** 分治法第三步:合并(1) --- 从分界点开始往左找到可能的点的最左边下标边界 */
index[L++] = i;
}
int Mid_Index = L; /** 记录往左找时, 第一个点的下标 */
for(int i = mid; i < right && p[i].x-p[mid-1].x < Min; i++)
{ /** 分治法第三步:合右边并(2) --- 从分界点开始往右找到可能的点的最右边的下标边界*/
index[L++] = i;
} double distance = INF;
for(int i = 0; i < Mid_Index; i++) /** 遍历往左找的点*/
{/** 分治法第三步:正式合并(3) --- dist(从左边选择的点, 从右边选择的点)*/
for(int j = Mid_Index; j < L; j++) /** 遍历往右找的点*/
{
Min = min(Min, dist(p[index[i]], p[index[j]])); /** 更新最短距离*/
}
}
return Min;
} int main()
{
int T;
int n,N;
scanf("%d", &T);
while(T--)
{
scanf("%d", &n);
N = 2*n;
for(int i = 0; i < n; i++)
{
scanf("%lf%lf", &p[i].x, &p[i].y);
p[i].flag = 0;
}
for(int i = n; i < N; i++)
{
scanf("%lf%lf", &p[i].x, &p[i].y);
p[i].flag = 1;
}
sort(p,p+N,cmp); double ans = min_dist(0, N);
printf("%.3lf\n", ans);
}
return 0;
}




poj 3714 Raid【(暴力+剪枝) || (分治法+剪枝)】的更多相关文章

  1. POJ 3714 Raid(计算几何の最近点对)

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

  2. 最近点对问题 POJ 3714 Raid && HDOJ 1007 Quoit Design

    题意:有n个点,问其中某一对点的距离最小是多少 分析:分治法解决问题:先按照x坐标排序,求解(left, mid)和(mid+1, right)范围的最小值,然后类似区间合并,分离mid左右的点也求最 ...

  3. POJ 3714 Raid(平面近期点对)

    解题思路: 分治法求平面近期点对.点分成两部分,加个标记就好了. #include <iostream> #include <cstring> #include <cst ...

  4. POJ 3714 Raid

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

  5. poj 3714 Raid(平面最近点对)

    Raid Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 7473   Accepted: 2221 Description ...

  6. POJ 1142 Smith Numbers(分治法+质因数分解)

    http://poj.org/problem?id=1142 题意: 给出一个数n,求大于n的最小数,它满足各位数相加等于该数分解质因数的各位相加. 思路:直接暴力. #include <ios ...

  7. POJ 3714 Raid 近期对点题解

    版权声明:本文作者靖心,靖空间地址:http://blog.csdn.net/kenden23/.未经本作者同意不得转载. https://blog.csdn.net/kenden23/article ...

  8. 【POJ 3714】Raid

    [题目链接]:http://poj.org/problem?id=3714 [题意] 给你两类的点; 各n个; 然后让你求出2*n个点中的最近点对的距离; 这里的距离定义为不同类型的点之间的距离; [ ...

  9. (洛谷 P1429 平面最近点对(加强版) || 洛谷 P1257 || Quoit Design HDU - 1007 ) && Raid POJ - 3714

    这个讲的好: https://phoenixzhao.github.io/%E6%B1%82%E6%9C%80%E8%BF%91%E5%AF%B9%E7%9A%84%E4%B8%89%E7%A7%8D ...

随机推荐

  1. Shell--变量键盘读取、数组与声明:read,array,declare

    1.read read [-pt] variable -P:后面可以接提示信息 -t:后面可以接等待的秒数,时间到后等待结束 read后面不加任何参数,直接加变量名称,那么就会主动出现一个空白行等待你 ...

  2. ISP模块之RAW DATA去噪(一)

    ISP(Image Signal Processor),图像信号处理器,主要用来对前端图像传感器输出信号处理的单元,主要用于手机,监控摄像头等设备上. RAW DATA,可以理解为:RAW图像就是CM ...

  3. Hadoop 变更磁盘的方法总结

    背景说明HDFS文件系统使用一段时间后,可能会出现磁盘空间不足或是磁盘损坏的现象,此时需要对DataNode节点的磁盘进行扩充或是更换,本文对操作流程做一个简单的总结 操作步骤 挂载硬盘 添加硬盘的操 ...

  4. Unity载入和内存管理机制

    Unity几种动态载入Prefab方式的差异: 事实上存在3种载入prefab的方式: 一是静态引用,建一个public的变量,在Inspector里把prefab拉上去,用的时候instantiat ...

  5. Java List序列化的实现

    概述 java中的序列化与反序列化都要求对象实现Serializable接口(其实就是声明一下),而对于List这种动态改变的集合默认是不实现这个接口的,也就是不能直接序列化.但是数组是可以序列化的, ...

  6. Solidworks 好的测试题模拟题

    题目:按照下图构建草图,注意设置必要的几何约束. 问题:   1.参照下图所示参数时请问其中绿色区域的面积为多少平方毫米?     题目:参照下图绘制草图轮廓,注意图中各线条之间均为相切过渡. 问题: ...

  7. 你真的了解装箱(Boxing)和拆箱(Unboxing)吗?

    所谓装箱就是装箱是将值类型转换为 object 类型或由此值类型实现的任一接口类型的过程.而拆箱就是反过来了.很多人可能都知道这一点,但是是否真的就很了解boxing和unboxing了呢?可以看下下 ...

  8. icvEvalCARTHaarClassifier

    /* *icvEvalCARTHaarClassifier *作用:通过计算haar特征值,来分配非叶子节点直到出现叶子节点,最后返回输出值val.  */ float icvEvalCARTHaar ...

  9. Volatile 多线程中用到的关键字

    前言 不管是在面试还是实际开发中 volatile 都是一个应该掌握的技能. 首先来看看为什么会出现这个关键字. 内存可见性 由于 Java 内存模型(JMM)规定,所有的变量都存放在主内存中,而每个 ...

  10. 打造Android万能上拉下拉刷新框架--XRefreshView(三)

    转载请注明出处:http://blog.csdn.net/footballclub/ 打造Android万能上拉下拉刷新框架–XRefreshView(一) 打造Android万能上拉下拉刷新框架–X ...