Bridge Across Islands
Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 7202   Accepted: 2113   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 NM. (3 ≤ NM ≤ 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

 
 
 
 
 
经典算法。
 
#include <stdio.h>
#include <algorithm>
#include <iostream>
#include <string.h>
#include <math.h>
using namespace std; const double eps = 1e-;
int sgn(double x)
{
if(fabs(x) < eps)return ;
if(x < )return -;
else return ;
}
struct Point
{
double x,y;
Point(double _x = 0.0,double _y = 0.0)
{
x = _x;
y = _y;
}
Point operator -(const Point &b)const
{
return Point(x - b.x, y - b.y);
}
double operator ^(const Point &b)const
{
return x*b.y - y*b.x;
}
double operator *(const Point &b)const
{
return x*b.x + y*b.y;
}
void input()
{
scanf("%lf%lf",&x,&y);
}
};
struct Line
{
Point s,e;
Line(){}
Line(Point _s,Point _e)
{
s = _s;
e = _e;
}
};
double dist(Point a,Point b)
{
return sqrt((a-b)*(a-b));
}
Point NearestPointToLineSeg(Point P,Line L)
{
Point result;
double t = ((P-L.s)*(L.e-L.s))/((L.e-L.s)*(L.e-L.s));
if(t >= && t <= )
{
result.x = L.s.x + (L.e.x - L.s.x)*t;
result.y = L.s.y + (L.e.y - L.s.y)*t;
}
else
{
if(dist(P,L.s) < dist(P,L.e))
result = L.s;
else result = L.e;
}
return result;
}
/*
* 求凸包,Graham算法
* 点的编号0~n-1
* 返回凸包结果Stack[0~top-1]为凸包的编号
*/
const int MAXN = ;
Point list[MAXN];
int Stack[MAXN],top;
//相对于list[0]的极角排序
bool _cmp(Point p1,Point p2)
{
double tmp = (p1-list[])^(p2-list[]);
if(sgn(tmp) > )return true;
else if(sgn(tmp) == && sgn(dist(p1,list[]) - dist(p2,list[])) <= )
return true;
else return false;
}
void Graham(int n)
{
Point p0;
int k = ;
p0 = list[];
//找最下边的一个点
for(int i = ;i < n;i++)
{
if( (p0.y > list[i].y) || (p0.y == list[i].y && p0.x > list[i].x) )
{
p0 = list[i];
k = i;
}
}
swap(list[k],list[]);
sort(list+,list+n,_cmp);
if(n == )
{
top = ;
Stack[] = ;
return;
}
if(n == )
{
top = ;
Stack[] = ;
Stack[] = ;
return ;
}
Stack[] = ;
Stack[] = ;
top = ;
for(int i = ;i < n;i++)
{
while(top > && sgn((list[Stack[top-]]-list[Stack[top-]])^(list[i]-list[Stack[top-]])) <= )
top--;
Stack[top++] = i;
}
}
//点p0到线段p1p2的距离
double pointtoseg(Point p0,Point p1,Point p2)
{
return dist(p0,NearestPointToLineSeg(p0,Line(p1,p2)));
}
//平行线段p0p1和p2p3的距离
double dispallseg(Point p0,Point p1,Point p2,Point p3)
{
double ans1 = min(pointtoseg(p0,p2,p3),pointtoseg(p1,p2,p3));
double ans2 = min(pointtoseg(p2,p0,p1),pointtoseg(p3,p0,p1));
return min(ans1,ans2);
}
//得到向量a1a2和b1b2的位置关系
double Get_angle(Point a1,Point a2,Point b1,Point b2)
{
Point t = b1 - ( b2 - a1 );
return (a2-a1)^(t-a1);
}
//旋转卡壳,求两个凸包的最小距离
double rotating_calipers(Point p[],int np,Point q[],int nq)
{
int sp = , sq = ;
for(int i = ;i < np;i++)
if(sgn(p[i].y - p[sp].y) < )
sp = i;
for(int i = ;i < nq;i++)
if(sgn(q[i].y - q[sq].y) > )
sq = i;
double tmp;
double ans = 1e99;
for(int i = ;i < np;i++)
{
while(sgn(tmp = Get_angle(p[sp],p[(sp+)%np],q[sq],q[(sq+)%nq])) < )
sq = (sq + )%nq;
if(sgn(tmp) == )
ans = min(ans,dispallseg(p[sp],p[(sp+)%np],q[sq],q[(sq+)%nq]));
else ans = min(ans,pointtoseg(q[sq],p[sp],p[(sp+)%np]));
sp = (sp+)%np;
}
return ans;
} double solve(Point p[],int n,Point q[],int m)
{
return min(rotating_calipers(p,n,q,m),rotating_calipers(q,m,p,n));
}
Point p[MAXN],q[MAXN];
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)==)
{
if(n == && m == )break;
for(int i = ;i < n;i++)
list[i].input();
Graham(n);
n = top;
for(int i = ;i < n;i++)
p[i] = list[Stack[i]];
for(int i = ;i < m;i++)
list[i].input();
Graham(m);
m = top;
for(int i = ;i < m;i++)
q[i] = list[Stack[i]];
printf("%.5lf\n",solve(p,n,q,m));
}
return ;
}
 
 
 
 
 

POJ 3608 Bridge Across Islands(旋转卡壳,两凸包最短距离)的更多相关文章

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

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

  2. ●POJ 3608 Bridge Across Islands

    题链: http://poj.org/problem?id=3608 题解: 计算几何,求两个凸包间的最小距离,旋转卡壳 两个凸包间的距离,无非下面三种情况: 所以可以基于旋转卡壳的思想,去求最小距离 ...

  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 3608 Bridge Across Islands(计算几何の旋转卡壳)

    Description Thousands of thousands years ago there was a small kingdom located in the middle of the ...

  5. POJ 3608 Bridge Across Islands (旋转卡壳)

    [题目链接] http://poj.org/problem?id=3608 [题目大意] 求出两个凸包之间的最短距离 [题解] 我们先找到一个凸包的上顶点和一个凸包的下定点,以这两个点为起点向下一个点 ...

  6. POJ 3608 Bridge Across Islands --凸包间距离,旋转卡壳

    题意: 给你两个凸包,求其最短距离. 解法: POJ 我真的是弄不懂了,也不说一声点就是按顺时针给出的,不用调整点顺序. 还是说数据水了,没出乱给点或给逆时针点的数据呢..我直接默认顺时针给的点居然A ...

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

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

  8. poj 3608 Bridge Across Islands 两凸包间最近距离

    /** 旋转卡壳,, **/ #include <iostream> #include <algorithm> #include <cmath> #include ...

  9. poj 3608 Bridge Across Islands

    题目:计算两个不相交凸多边形间的最小距离. 分析:计算几何.凸包.旋转卡壳.分别求出凸包,利用旋转卡壳求出对踵点对,枚举距离即可. 注意:1.利用向量法判断旋转,而不是计算角度:避免精度问题和TLE. ...

随机推荐

  1. python基础===isinstance() 函数,判断一个对象是否是一个已知的类型

    isinstance(object, classinfo) object -- 实例对象. classinfo -- 可以是直接或间接类名.基本类型或者有它们组成的元组. >>>a ...

  2. C#数据没初始化,使用会报错,可以初始化null

    protected void Page_Load(object sender, EventArgs e) { string[] A; if (B== 0) { A = new string[] {1, ...

  3. C#使用Linq To XML读取XML,Linq生成XML,Linq创建带属性或带节点XML

    using System; using System.Linq; using System.Xml.Linq; namespace Sample2 { class Program { static v ...

  4. shell 智能获取历史记录功能

    vim ~/.inputrc 文件内容: "\e[A": history-search-backward"\e[B": history-search-forwa ...

  5. 【COGS2622】后缀平衡树

    这是个后缀平衡树的裸题.... 然后傻逼的我调了一下午. #include<bits/stdc++.h> typedef long long ll; using namespace std ...

  6. 【UOJ#169】元旦老人与数列

    论文题. 考虑到这题的维护和区间操作是反向的,也就是说无法像V那题快速的合并标记. 我们知道,一个区间的最小值和其他值是可以分开来维护的,因为如果一个区间被整体覆盖,那么最小值始终是最小值. 对于被覆 ...

  7. vue-cli脚手架引入element UI的正确打开方式

    element UI官网教程:http://element-cn.eleme.io/#/zh-CN/component/quickstart 1.完整引入,直接了当,但是组件文件不是按需加载,造成多余 ...

  8. mysql数据库隔离级别

    # 原创,转载请留言联系 事务的隔离级别 (由高到低)1.串行化(serializable):一个事务一个事务的执行2.可重复读(Repeatable-Read) 可重复读,无论其他事务是否修改并提交 ...

  9. pom报错解决方法大全

    1.Failure to transfer org.apache.maven.plugins:maven-surefire-plugin:pom 解决方法: Windows: CMD --> c ...

  10. linux命令行任务管理

    今天看到了linux命令行的任务管理命令感觉很实用: 1.ctrl+z  将当前前台执行的任务放到后台并暂停 2.fg恢复上次放入后台的任务 这两个命令组合起来很实用,比如在linux命令行中写pyt ...