poj 3714 Raid【(暴力+剪枝) || (分治法+剪枝)】
题目:
|
Raid
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 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 Input The first line is a integer T representing the number of test cases. Output For each test case output the minimum distance with precision of three decimal placed in a separate line. Sample Input 2 Sample Output 1.414 Source |
题意:
算法:
分治法:
代码:
/****************************************************************
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【(暴力+剪枝) || (分治法+剪枝)】的更多相关文章
- POJ 3714 Raid(计算几何の最近点对)
Description After successive failures in the battles against the Union, the Empire retreated to its ...
- 最近点对问题 POJ 3714 Raid && HDOJ 1007 Quoit Design
题意:有n个点,问其中某一对点的距离最小是多少 分析:分治法解决问题:先按照x坐标排序,求解(left, mid)和(mid+1, right)范围的最小值,然后类似区间合并,分离mid左右的点也求最 ...
- POJ 3714 Raid(平面近期点对)
解题思路: 分治法求平面近期点对.点分成两部分,加个标记就好了. #include <iostream> #include <cstring> #include <cst ...
- POJ 3714 Raid
Description After successive failures in the battles against the Union, the Empire retreated to its ...
- poj 3714 Raid(平面最近点对)
Raid Time Limit: 5000MS Memory Limit: 65536K Total Submissions: 7473 Accepted: 2221 Description ...
- POJ 1142 Smith Numbers(分治法+质因数分解)
http://poj.org/problem?id=1142 题意: 给出一个数n,求大于n的最小数,它满足各位数相加等于该数分解质因数的各位相加. 思路:直接暴力. #include <ios ...
- POJ 3714 Raid 近期对点题解
版权声明:本文作者靖心,靖空间地址:http://blog.csdn.net/kenden23/.未经本作者同意不得转载. https://blog.csdn.net/kenden23/article ...
- 【POJ 3714】Raid
[题目链接]:http://poj.org/problem?id=3714 [题意] 给你两类的点; 各n个; 然后让你求出2*n个点中的最近点对的距离; 这里的距离定义为不同类型的点之间的距离; [ ...
- (洛谷 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 ...
随机推荐
- Ubuntu使用日志2(在Eclipse中搭建C++交叉编译环境)
Release用交叉编译:arm-none-linux-gnueabi-gcc. 搭建步骤: 1).在Project->Properties->C/C++ Build->Settin ...
- 飘逸的python - __get__ vs __getattr__ vs __getattribute__以及属性的搜索策略
差别: __getattribute__:是无条件被调用.对不论什么对象的属性訪问时,都会隐式的调用__getattribute__方法,比方调用t.__dict__,事实上运行了t.__getatt ...
- TCP/IP 网络编程(五)
优于 select 的 epoll (I/O 复用) select 速度慢的原因 调用select后针对全部文件描写叙述符的循环 每次调用函数时都须要向该函数传递监视对象信息 select并非把发生变 ...
- 通知传值(NSNotificationCenter)
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvenVveW91MTMxNA==/font/5a6L5L2T/fontsize/400/fill/I0JBQk ...
- 已经入了vim的坑
一.移动光标 1.左移h.右移l.下移j.上移k 2.向下翻页ctrl + f,向上翻页ctrl + b 3.向下翻半页ctrl + d,向上翻半页ctrl + u 4.移动到行尾$,移动到行首0(数 ...
- PHP实现查看邮件是否被阅读
<? //当你在发送邮件时,你或许很想知道该邮件是否被对方已阅读.这里有段非常有趣的代码片段能够显示对方IP地址记录阅读//的实际日期和时间. error_reporting(0); Hea ...
- SQL的四种连接
SQL的四种连接-内连接.左外连接.右外连接.全连接 今天在看一个遗留系统的数据表的时候发现平时查找的视图是FULL OUT JOIN的,导致平时的数据记录要进行一些限制性处理,其实也可以设置视图 ...
- c#关于路径的总结(转) 虚拟路径波浪号~和斜杠/的区别
c#关于路径的总结(转) 来源:http://www.cnblogs.com/yugongmengjiutian/articles/5521165.html 前一段时间写代码时经常遇到获取路径问题 ...
- destroy其他所有activity
Intent intent = new Intent(ActivityA.this, ActivityB.class);intent.setFlags(Intent.FLAG_ACTIVITY_NEW ...
- <!DOCTYPE>奇葩的问题
作用:<!DOCTYPE> 声明不是 HTML 标签:它是指示 web 浏览器关于页面使用哪个 HTML 版本号进行编写的指令. 1.:<!DOCTYPE> 声明没有结束标签. ...