poj 3608(旋转卡壳求解两凸包之间的最短距离)
| Time Limit: 1000MS | Memory Limit: 65536K | |||
| Total Submissions: 9768 | Accepted: 2866 | Special Judge | ||
Description
Thousands of thousands years ago there was a small kingdom located in the middle of the Pacific Ocean. The territory of the kingdom consists two separated islands. Due to the impact of the ocean current, the shapes of both the islands became convex polygons. The king of the kingdom wanted to establish a bridge to connect the two islands. To minimize the cost, the king asked you, the bishop, to find the minimal distance between the boundaries of the two islands.

Input
The input consists of several test cases.
Each test case begins with two integers N, M. (3 ≤ N, M ≤ 10000)
Each of the next N lines contains a pair of coordinates, which describes the position of a vertex in one convex polygon.
Each of the next M lines contains a pair of coordinates, which describes the position of a vertex in the other convex polygon.
A line with N = M = 0 indicates the end of input.
The coordinates are within the range [-10000, 10000].
Output
For each test case output the minimal distance. An error within 0.001 is acceptable.
Sample Input
4 4
0.00000 0.00000
0.00000 1.00000
1.00000 1.00000
1.00000 0.00000
2.00000 0.00000
2.00000 1.00000
3.00000 1.00000
3.00000 0.00000
0 0
Sample Output
1.00000 引自:http://blog.csdn.net/acmaker/article/details/3178696
两个凸多边形 P 和 Q 之间的最小距离由多边形间的对踵点对确立。 存在凸多边形间的三种多边形间的对踵点对, 因此就有三种可能存在的最小距离模式:
- “顶点-顶点”的情况
- “顶点-边”的情况
- “边-边”的情况
换句话说, 确定最小距离的点对不一定必须是顶点。 下面的三个图例表明了以上结论:



给定结果, 一个基于旋转卡壳的算法自然而然的产生了:
考虑如下的算法, 算法的输入是两个分别有 m 和 n 个逆时针给定顶点的凸多边形 P 和 Q。
- 计算 P 上 y 坐标值最小的顶点(称为 yminP ) 和 Q 上 y 坐标值最大的顶点(称为 ymaxQ)。
- 为多边形在 yminP 和 ymaxQ 处构造两条切线 LP 和 LQ 使得他们对应的多边形位于他们的右侧。 此时 LP 和 LQ 拥有不同的方向, 并且 yminP 和 ymaxQ 成为了多边形间的一个对踵点对。
- 计算距离(yminP,ymaxQ) 并且将其维护为当前最小值。
- 顺时针同时旋转平行线直到其中一个与其所在的多边形的边重合。
- 如果只有一条线与边重合, 那么只需要计算“顶点-边”对踵点对和“顶点-顶点”对踵点对距离。 都将他们与当前最小值比较, 如果小于当前最小值则进行替换更新。 如果两条切线都与边重合, 那么情况就更加复杂了。 如果边“交叠”, 也就是可以构造一条与两条边都相交的公垂线(但不是在顶点处相交), 那么就计算“边-边”距离。 否则计算三个新的“顶点-顶点”对踵点对距离。 所有的这些距离都与当前最小值进行比较, 若小于当前最小值则更新替换。
- 重复执行步骤4和步骤5, 直到新的点对为(yminP,ymaxQ)。
- 输出最小距离。
模板如下:
/*
叉积的一个非常重要的性质是可以通过它的符号来判断两矢量相互之间的顺逆时针关系:
若 P * Q > 0,则 P 在 Q 的顺时针方向;
若 P * Q < 0, 则 P 在 Q 的逆时针方向;
若 P * Q = 0,则 P 与 Q 共线,但不确定 P, Q 的方向是否相同;
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <math.h>
#include <algorithm>
using namespace std;
const double esp = 1e-;
const int N = ;
struct Point
{
double x,y;
} p[N],q[N];
int n,m;
///叉积
double mult_cross(Point a,Point b,Point c)
{
return (a.x-c.x)*(b.y-c.y)-(b.x-c.x)*(a.y-c.y);
}
///点积
double mult_point(Point a,Point b,Point c){
return (a.x-c.x)*(b.x-c.x)+(a.y-c.y)*(b.y-c.y);
}
///距离
double dis(Point a,Point b)
{
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
///将点集按照逆时钟排序
void clockwise_sort(Point p[],int n){
for(int i=;i<n-;i++){
double tmp = mult_cross(p[i+],p[i+],p[i]);
if(tmp>) return;
else if(tmp<){
reverse(p,p+n);
return;
}
}
}
///点c到直线ab的最短距离
double GetDist(Point a,Point b,Point c){
if(dis(a,b)<esp) return dis(b,c); ///a,b是同一个点
if(mult_point(b,c,a)<-esp) return dis(a,c); ///投影
if(mult_point(a,c,b)<-esp) return dis(b,c);
return fabs(mult_cross(b,c,a)/dis(a,b)); }
///求一条线段ab的两端点到另外一条线段bc的距离,反过来一样,共4种情况
double MinDist(Point a,Point b,Point c,Point d){
return min(min(GetDist(a,b,c),GetDist(a,b,d)),min(GetDist(c,d,a),GetDist(c,d,b)));
} double min_PQ(Point p[],Point q[],int n,int m){
int yminP = ,ymaxQ=;
for(int i=;i<n;i++){ ///找到点集p组成的凸包的左下角
if(p[i].y<p[yminP].y||(p[i].y==p[yminP].y)&&(p[i].x<p[yminP].x)) yminP = i;
}
for(int i=;i<m;i++){ ///找到点集q组成的凸包的右上角
if(q[i].y>q[ymaxQ].y||(q[i].y==q[ymaxQ].y)&&(q[i].x>q[ymaxQ].x)) ymaxQ = i;
}
double ans = dis(p[yminP],q[ymaxQ]); ///距离(yminP,ymaxQ)维护为当前最小值。
p[n]=p[],q[m]=q[];
for(int i=;i<n;i++){
double tmp;
while(tmp=(mult_cross(q[ymaxQ+],p[yminP],p[yminP+])-mult_cross(q[ymaxQ],p[yminP],p[yminP+]))>esp)
ymaxQ = (ymaxQ+)%m;
if(tmp<-esp) ans = min(ans,GetDist(p[yminP],p[yminP+],q[ymaxQ]));
else ans=min(ans,MinDist(p[yminP],p[yminP+],q[ymaxQ],q[ymaxQ+]));
yminP = (yminP+)%n;
}
return ans;
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF,n+m)
{
for(int i=; i<n; i++)
{
scanf("%lf%lf",&p[i].x,&p[i].y);
}
for(int i=; i<m; i++)
{
scanf("%lf%lf",&q[i].x,&q[i].y);
}
clockwise_sort(p,n);
clockwise_sort(q,m);
double ans = min(min_PQ(p,q,n,m),min_PQ(q,p,m,n));
printf("%.5lf\n",ans);
}
return ;
}
poj 3608(旋转卡壳求解两凸包之间的最短距离)的更多相关文章
- poj 3608 旋转卡壳求不相交凸包最近距离;
题目链接:http://poj.org/problem?id=3608 #include<cstdio> #include<cstring> #include<cmath ...
- POJ 3608 Bridge Across Islands(旋转卡壳,两凸包最短距离)
Bridge Across Islands Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 7202 Accepted: ...
- poj 2079(旋转卡壳求解凸包内最大三角形面积)
Triangle Time Limit: 3000MS Memory Limit: 30000K Total Submissions: 9060 Accepted: 2698 Descript ...
- Bridge Across Islands POJ - 3608 旋转卡壳求凸包最近距离
\(\color{#0066ff}{题目描述}\) 几千年前,有一个小王国位于太平洋的中部.王国的领土由两个分离的岛屿组成.由于洋流的冲击,两个岛屿的形状都变成了凸多边形.王国的国王想建立一座桥来连接 ...
- 「POJ-3608」Bridge Across Islands (旋转卡壳--求两凸包距离)
题目链接 POJ-3608 Bridge Across Islands 题意 依次按逆时针方向给出凸包,在两个凸包小岛之间造桥,求最小距离. 题解 旋转卡壳的应用之一:求两凸包的最近距离. 找到凸包 ...
- poj 3608 Bridge Across Islands 两凸包间最近距离
/** 旋转卡壳,, **/ #include <iostream> #include <algorithm> #include <cmath> #include ...
- POJ 3608 旋转卡壳
思路: 旋转卡壳应用 注意点&边 边&边 点&点 三种情况 //By SiriusRen #include <cmath> #include <cstdi ...
- POJ3608(旋转卡壳--求两凸包的最近点对距离)
题目:Bridge Across Islands 分析:以下内容来自:http://blog.csdn.net/acmaker/article/details/3178696 考虑如下的算法, 算法的 ...
- Poj 2187 旋转卡壳
Poj 2187 旋转卡壳求解 传送门 旋转卡壳,是利用凸包性质来求解凸包最长点对的线性算法,我们逐渐改变每一次方向,然后枚举出这个方向上的踵点对(最远点对),类似于用游标卡尺卡着凸包旋转一周,答案就 ...
随机推荐
- 判断python字典中key是否存在的两种方法
今天来说一下如何判断字典中是否存在某个key,一般有两种通用做法,下面为大家来分别讲解一下: 第一种方法:使用自带函数实现. 在python的字典的属性方法里面有一个has_key()方法,这个方法使 ...
- C语言数组作业总结
数组作业总结 评分注意事项. 注意用Markdown语法排版,尤其注意伪代码用代码符号渲染.用符号 ``` 生成代码块. 变量名不规范,没注释,没缩进,括号不对齐,倒扣5分. PTA上写的所有代码务必 ...
- SQL select 和SQL where语句
一.SQL SELECT语句 用于从表中选取数据,结果被存储在一共结果表中(称为结果集) 1.语法: SELECT 列名称 FROM 表名称 以及: SELECT * FROM 表名称 注:SQ ...
- Java IO 之 File 的创建、重命名与遍历
File表示存储设备上的一个文件或目录,使用方式查看API即可,比较简单 package org.zln.io.file; import java.io.File; /** * Created by ...
- Python数据分析(一)pandas数据切片
1.获取行或列数据 loc——通过行标签索引行数据 iloc——通过行号索引行数据 ix——通过行标签或者行号索引行数据(基于loc和iloc 的混合) 同理,索引列数据也是如此! import pa ...
- P4754 True Vegetable
题目描述 小A现在有 NN 道题,编号为 1,2,\cdots,N1,2,⋯,N .每道题的起始毒瘤程度为 00 或 11 .在每回合,小A可以将编号连续的 KK 道题的毒瘤程度+1.但小B因为本身比 ...
- Hibernate查询语言——HQL
HQL(Hibernate Query Language)查询语言是完全面向对象的查询语言,它提供了更加面向对象的封装,可以理解如多态.继承和关联. HQL的基本语法如下: select " ...
- Intel QuickAssist Technology and OpenSSL – Benchmarks and Setup Tips
Intel QuickAssist Technology and OpenSSL – Benchmarks and Setup Tips 来源:https://www.servethehome.com ...
- hihoCoder #1872 : Pythagorean triple
此题是 2018 年 ICPC Asia Beijing Regional Contest 的 C 题. 题目大意 求斜边长度不超过 $n$($ n \le 10^9$) 的勾股数的数量.不计两直角边 ...
- 【BZOJ 1070】[SCOI2007]修车 费用流
就是拆个点限制一下(两点一排一大片),这道题让我注意到了限制这个重要的词.我们跑网络流跑出来的图都是有一定意义的,一般这个意义就对应了问题的一种方案,一般情况下跑一个不知道对不对的方案是相对容易的我们 ...