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 旋转卡壳求解 传送门 旋转卡壳,是利用凸包性质来求解凸包最长点对的线性算法,我们逐渐改变每一次方向,然后枚举出这个方向上的踵点对(最远点对),类似于用游标卡尺卡着凸包旋转一周,答案就 ...
随机推荐
- spring MVC 字符串数组传值 字符带有逗号,问题
按照如下图所示方式传值,想在后台得到一个长度为1的数组,后台直接根据,进行分割,就得到长度为2的数组 1.曲线救国解决法 解决方案, 前端对参数进行编码 encodeURIComponent(valu ...
- struts标签中的select
<!-- Struts下拉列表标签: name="deptId" 下拉列表标签的名称(服务器根据这个名称获取选择的项的实际的值value值) headerKey 默认选择项的 ...
- input属性 disabled与readonly的区别
从效果上看 源码 <!DOCTYPE html> <html> <head lang="en"> <meta charset=" ...
- HTML5<canvas>标签:使用canvas元素在网页上绘制渐变和图像(2)
详细解释HTML5 Canvas中渐进填充的参数设置与使用,Canvas中透明度的设置与使用,结合渐进填充与透明度支持,实现图像的Mask效果. 一:渐进填充(Gradient Fill) Canva ...
- P1196 [NOI2002]银河英雄传说
题目描述 公元五八○一年,地球居民迁至金牛座α第二行星,在那里发表银河联邦创立宣言,同年改元为宇宙历元年,并开始向银河系深处拓展. 宇宙历七九九年,银河系的两大军事集团在巴米利恩星域爆发战争.泰山压顶 ...
- BZOJ1857 [Scoi2010]传送带 【三分法】
题目链接 BZOJ1857 题解 画画图就发现实际上是在\(AB\)上和\(CD\)上分别选两个点\(E\),\(F\),使得\(t_{AE} + t_{EF} + t_{FD}\)最小 然后猜想到当 ...
- readelf用法小记
By francis_hao Feb 14,2017 显示ELF文件的信息 用法概述 readelf和objdump类似,不过,readelf会显示更详细的信息,而且独立于BFD库,因此当BFD ...
- MySQL使用笔记(三)表的操作
By francis_hao Dec 11,2016 表的操作 表的操作有创建表.查看表.删除表和修改表 创建表 创建表之前要在某个数据库中. mysql> create table ta ...
- bzoj 3720 Gty的妹子树 树分块?瞎搞
Gty的妹子树 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2149 Solved: 781[Submit][Status][Discuss] D ...
- Ubuntu系统iptables规则的查看和清除
系统不支持service iptables restart,service iptables status,如何查看与清除iptable的规则呢? 一 iptables查看基本语法 iptables ...