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 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

 
 
 
 
 
经典算法。
 
#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. ASPxTreeList的右键按钮事件

    ASPxTreeList应该是比较长用的控件了~现在就来说说它的右键按钮事件 这里实现的是右键里有折合和展开所有节点的功能 code: <dx:ASPxTreeList ID="ASP ...

  2. leetcode 之Remove Nth Node From End of List(19)

    这题比较简单,方法有很多.其中一种比较有意思的做法是设置两个指针,一个先走n步,然后再一起走.一个到了末尾,另一个也就确定了要删除元素的位置. ListNode *removeNthFromEnd(L ...

  3. MySQL的七种join

    转载 原文地址 建表 在这里我们先建立两张有外键关联的两张表: CREATE DATABASE db0206; USE db0206; CREATE TABLE `db0206`.`tbl_dept` ...

  4. 八:Zookeeper开源客户端Curator的api测试

    curator是Netflix公司开源的一套ZooKeeper客户端,Curator解决了很多ZooKeeper客户端非常底层的细节开发工作.包括连接重连,反复注册Watcher等.实现了Fluent ...

  5. ffmepg的基本使用

    基本使用命令 ffmpeg -i input.mp4 output.avi //视频格式转换 ffmepg -i input.mp4 -r fps image%3d.jpg //视频转成图片 //fp ...

  6. vue利用watch侦听对象具体的属性 ~ 巧用计算属性computed做中间层

    有时候需要侦听某个对象具体的属性,可以按下面案例进行: <template> <div> <input type="text" v-model=&qu ...

  7. AngularJS之页面跳转Route

    1.除了引用AngularJs.js外,还要引用路由JS, "~/Scripts/angularjs/angular-route.js" 2.通过$routeProvider定义路 ...

  8. 【Mac电脑】Jenkins的安装

    1.JDK自己下载安装喽, 2.下载Jenkins 下载路径:https://mirrors.tuna.tsinghua.edu.cn/jenkins/war-stable/2.121.1/jenki ...

  9. 一次cloudstack启动cloudstack-agent报错的处理过程

    http://www.bubuko.com/infodetail-2397888.html

  10. AC日记——[ZJOI2015]幻想乡战略游戏 洛谷 P3345

    [ZJOI2015]幻想乡战略游戏 思路: 树剖暴力转移: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 1 ...