Bridge Across Islands
Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 11539   Accepted: 3395   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

Source

 
图示:

思路:找到凸包 p 的 y 值最小点 yminP 和 q 的 y 值最大点ymaxQ,然后分别做切如图。那么AC×AD>AC×AB则说明B还不是离AC最近的点,所以++ymaxQ。

否则用 AC和 BD 两个线段的距离更新最近距离,并且++yminP,即考察P的下一条边。

具体实现时,同时旋转体现为逐步选取逆时针方向上的下一个顶点作为C或D、A或B,其实选择卡壳就是只要找到"当前向量面积不小于下一个向量面积"即可,再求两条线段间的最短距离。

代码:

 //#include "bits/stdc++.h"
#include "cstdio"
#include "map"
#include "set"
#include "cmath"
#include "queue"
#include "vector"
#include "string"
#include "cstring"
#include "time.h"
#include "iostream"
#include "stdlib.h"
#include "algorithm"
#define db double
#define ll long long
#define vec vector<ll>
#define mt vector<vec>
#define ci(x) scanf("%d",&x)
#define cd(x) scanf("%lf",&x)
#define cl(x) scanf("%lld",&x)
#define pi(x) printf("%d\n",x)
#define pd(x) printf("%f\n",x)
#define pl(x) printf("%lld\n",x)
//#define rep(i, x, y) for(int i=x;i<=y;i++)
#define rep(i,n) for(int i=0;i<n;i++)
const int n = 1e4 + ;
const int mod = 1e9 + ;
const int mOD = mod - ;
const db eps = 1e-;
const db PI = acos(-1.0);
const int inf=0x3f3f3f3f;
using namespace std;
struct P
{
db x, y;
P() {}
P(db x, db y) : x(x), y(y) {}
P operator + (const P& p){ return P(x + p.x, y + p.y); }
P operator - (const P& p){ return P(x - p.x, y - p.y); }
P operator * (const db& d){ return P(x * d, y * d); }
bool operator < (const P& a) const
{
if (x != a.x) return x < a.x;
else return y < a.y;
}
db dot(const P& p) { return x * p.x + y * p.y; }
db det(const P& p) { return x * p.y - y * p.x; }
};
P p[n], q[n];
// 向量AB 与 AC 的叉积 如果叉积大于0,那么C在向量AB的逆时针方向,叉积小于0则在AB的顺时针方向。如果叉积等于0,则ABC共线。
db cross(P A, P B, P C) {return (B - A).det(C - A); }
// 向量AB 与 AC 的点积 如果点积的结果为0,那么这两个向量互相垂直
db mul(P A, P B, P C) {return (B - A).dot(C - A); }
// 两点距离
db dis(P A, P B){return sqrt((A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y)); } // 逆时针排序
void csort(P* p, int n)
{
for (int i = ; i < n - ; ++i)
{
db tmp = cross(p[i], p[i + ], p[i + ]);
if (tmp > eps) return;
else if (tmp < -eps)
{
reverse(p, p + n);
return;
}
}
} //计算C点到线段AB的最短距离
db ptl(P A, P B, P C)
{
if (dis(A, B) < eps) return dis(B, C);
if (mul(A, B, C) < -eps) return dis(A, C);
if (mul(B, A, C) < -eps) return dis(B, C);
return fabs(cross(A, B, C) / dis(A, B));
}
//求一条线段的两端点到另外一条线段的距离,反过来一样,共4种情况
db ltl(P A, P B, P C, P D)
{
return min(min(ptl(A, B, C), ptl(A, B, D)), min(ptl(C, D, A), ptl(C, D, B)));
}
db solve(P* p, P* q, int n, int m)
{
int pmi = , qmx = ;
for (int i = ; i < n; ++i) if (p[i].y < p[pmi].y) pmi = i; // P上y坐标最小的顶点
for (int i = ; i < m; ++i) if (q[i].y > q[qmx].y) qmx = i; // Q上y坐标最大的顶点
p[n] = p[]; // 为了方便,避免求余
q[m] = q[];
db tmp, ans = inf;
for (int i = ; i < n; ++i)
{
while (tmp = cross(p[pmi],p[pmi + ], q[qmx + ]) - cross(p[pmi],p[pmi + ], q[qmx]) > eps) qmx = (qmx + ) % m;
ans = min(ans, ltl(p[pmi], p[pmi + ], q[qmx], q[qmx + ]));
pmi = (pmi + ) % n;
}
return ans;
}
int main()
{
int n, m;
while (~scanf("%d%d", &n, &m) && n + m)
{
for (int i = ; i < n; ++i) cd(p[i].x),cd(p[i].y);
for (int i = ; i < m; ++i) cd(q[i].x),cd(q[i].y);
csort(p, n);
csort(q, m);
printf("%.5lf\n", solve(p, q, n, m));
}
return ;
}

POJ 3608 凸包间最短距离(旋转卡壳)的更多相关文章

  1. poj 3608 凸包间的最小距离

    Bridge Across Islands Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 7632   Accepted:  ...

  2. POJ 3608 Bridge Across Islands [旋转卡壳]

    Bridge Across Islands Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 10455   Accepted: ...

  3. POJ 2187 Beauty Contest【旋转卡壳求凸包直径】

    链接: http://poj.org/problem?id=2187 http://acm.hust.edu.cn/vjudge/contest/view.action?cid=22013#probl ...

  4. 【POJ 2187】Beauty Contest(凸包直径、旋转卡壳)

    给定点集的最远两点的距离. 先用graham求凸包.旋(xuán)转(zhuàn)卡(qiǎ)壳(ké)求凸包直径. ps:旋转卡壳算法的典型运用 http://blog.csdn.net/hanch ...

  5. [Bzoj1069][Scoi2007]最大土地面积(凸包)(旋转卡壳)

    1069: [SCOI2007]最大土地面积 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 3629  Solved: 1432[Submit][Sta ...

  6. [模板] 计算几何2: 自适应Simpson/凸包/半平面交/旋转卡壳/闵可夫斯基和

    一些基本的定义在这里: [模板] 计算几何1(基础): 点/向量/线/圆/多边形/其他运算 自适应Simpson Simpson's Rule: \[ \int ^b_a f(x)dx\approx ...

  7. POJ - 2079:Triangle (旋转卡壳,求最大三角形)

    Given n distinct points on a plane, your task is to find the triangle that have the maximum area, wh ...

  8. POJ - 3608 Bridge Across Islands【旋转卡壳】及一些有趣现象

    给两个凸包,求这两个凸包间最短距离 旋转卡壳的基础题 因为是初学旋转卡壳,所以找了别人的代码进行观摩..然而发现很有意思的现象 比如说这个代码(只截取了关键部分) double solve(Point ...

  9. poj 2187 凸包加旋转卡壳算法

    题目链接:http://poj.org/problem?id=2187 旋转卡壳算法:http://www.cppblog.com/staryjy/archive/2009/11/19/101412. ...

随机推荐

  1. Python常用模块(四)

    一.re模块 正则表达式时计算机科学的一个概念,正则表达式通常被用来检索,替换那些符合某个模式的文本,大多数程序设计语言都支持利用正则表达式进行字符串操作. 正则就是用一些具有特殊含义的符号组合到一起 ...

  2. SublimeText插件autoprefixer : css 添加前续

    /* 使用前 */ body { background: linear-gradient(to bottom, #DADADA, #000); } p a { -webkit-border-radiu ...

  3. http-equiv和name的区别

    meta是用来在HTML文档中模拟HTTP协议的响应头报文.meta 标签用于网页的<head>与</head>中,meta 标签的用处很多.meta 的属性有两种:name和 ...

  4. zookeeper的几种使用场景

    1.数据的发布与订阅 通过发布与订阅实现配置的信息的统一管理,主要采用zk节点可以存储数据的特性,我们可以将一些配置信息存放到某一节点上,订阅这个节点的服务就可以动态的获取这个节点的数据.在应用启动的 ...

  5. python数组列表、字典、拷贝、字符串

    python中字符串方法 name = "I teased at life as if it were a foolish game" print(name.capitalize( ...

  6. 使用C语言来实现模块化

    除了C语言以及C++编程语言之外,在其它现在非常流行的开发语言中,比如说:java,php,jsp等等.我们很难想象到缺少标准化的模块管理机制是一件多么可怕的事情.但是这往往也是由C语言本身的设计哲学 ...

  7. Python基本数据类型(一)

    一.int的函数说明(部分函数Python2特有,Python3已删除,部分函数Python3新增:) class int(object): """ int(x=0) - ...

  8. PHP : url中出现乱码问题

    例子: 在html中,将数据传到url中 当我点击“提交回复”后,跳转页面中将显示: 我们获取这个参数: 但是由于传过来的参数是中文,url会进行自动的解析成二进制的代码,那我们后台接受到的数据是解析 ...

  9. 我的visual studio 配色方案 Rubik c++版

    只是更改了c++的配色,放出来与大家分享,因为大胆地采用了各种颜色,所以我把它取名叫做Rubik,因为Rubik‘s cube也就是魔方,我本人是非常喜欢魔方的,然后也符合颜色丰富多彩的这个特征,希望 ...

  10. java ——String , StringBuffer, StringBuilder类

    一.String类概述 1.String对象一旦创建就不能改变. 2.字符串常量池. 字符串常量池的特点:池中有则直接使用,池中没有则创建新的字符串常量. 例1: “==”  比较两个对象是否引用同一 ...