POJ 3608 Bridge Across Islands(计算几何の旋转卡壳)
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.
题目大意:给两个凸多边形,求两个凸多边形的最近距离
思路:用旋转卡壳,最短距离一定在两条支撑线之间(相当于切线吧大概……),详见代码,表达能力渣渣
PS:此题虽然没说点的顺序,DISCUSS里面有人说是乱序的,但实际上好像是逆序的(反正我不考虑点的顺序也能过就是了……)
代码(125MS):
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std; #define EPS 1e-8
#define MAXN 10010 inline int sgn(double x) {
if(fabs(x) < EPS) return ;
return x > ? : -;
} struct Point {
double x, y;
Point(double xx = , double yy = ): x(xx), y(yy) {}
};
//cross
inline double operator ^ (const Point &a, const Point &b) {
return a.x * b.y - a.y * b.x;
} inline double operator * (const Point &a, const Point &b) {
return a.x * b.x + a.y * b.y;
} inline Point operator - (const Point &a, const Point &b) {
return Point(a.x - b.x, a.y - b.y);
} inline double dist(const Point &a, const Point &b) {
return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
} inline double Cross(Point o, Point s, Point e) {
return (s - o) ^ (e - o);
} struct Line {
Point s, e;
Line() {}
Line(Point ss, Point ee): s(ss), e(ee) {}
}; inline double Point_to_Line(const Point &p, const Line &L) {
return fabs(Cross(p, L.s, L.e)/dist(L.s, L.e));
} inline double Point_to_Seg(const Point &p, const Line &L) {
if(sgn((L.e - L.s) * (p - L.s)) < ) return dist(p, L.s);
if(sgn((L.s - L.e) * (p - L.e)) < ) return dist(p, L.e);
return Point_to_Line(p, L);
} inline double Seg_to_Seg(const Line &a, const Line &b) {
double ans1 = min(Point_to_Seg(a.s, b), Point_to_Seg(a.e, b));
double ans2 = min(Point_to_Seg(b.s, a), Point_to_Seg(b.e, a));
return min(ans1, ans2);
} inline double solve(Point *p, Point *q, int np, int nq) {
p[np] = p[];
q[nq] = q[];
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, ans = dist(p[], q[]);
for(int i = ; i < np; ++i) {
while(sgn(tmp = (Cross(q[sq], p[sp], p[sp+]) - Cross(q[sq+],p[sp],p[sp+]))) < )
sq = (sq + ) % nq;
if(sgn(tmp) > )
ans = min(ans, Point_to_Seg(q[sq], Line(p[sp], p[sp+])));
else
ans = min(ans, Seg_to_Seg(Line(p[sp], p[sp+]), Line(q[sq], q[sq+])));
sp = (sp + ) % np;
}
return ans;
} Point p[MAXN], q[MAXN];
int np, nq; int main() {
while(scanf("%d%d", &np, &nq) != EOF) {
if(np == && nq == ) break;
for(int i = ; i < np; ++i)
scanf("%lf%lf", &p[i].x, &p[i].y);
for(int i = ; i < nq; ++i)
scanf("%lf%lf", &q[i].x, &q[i].y);
printf("%f\n", min(solve(p, q, np, nq), solve(q, p, nq, np)));
}
return ;
}
代码(141MS)(高度模板化):
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std; const int MAXN = ;
const double EPS = 1e-;
const double PI = acos(-1.0);//3.14159265358979323846
const double INF = ; inline int sgn(double x) {
return (x > EPS) - (x < -EPS);
} struct Point {
double x, y, ag;
Point() {}
Point(double x, double y): x(x), y(y) {}
void read() {
scanf("%lf%lf", &x, &y);
}
bool operator == (const Point &rhs) const {
return sgn(x - rhs.x) == && sgn(y - rhs.y) == ;
}
bool operator < (const Point &rhs) const {
if(y != rhs.y) return y < rhs.y;
return x < rhs.x;
}
Point operator + (const Point &rhs) const {
return Point(x + rhs.x, y + rhs.y);
}
Point operator - (const Point &rhs) const {
return Point(x - rhs.x, y - rhs.y);
}
Point operator * (const double &b) const {
return Point(x * b, y * b);
}
Point operator / (const double &b) const {
return Point(x / b, y / b);
}
double operator * (const Point &rhs) const {
return x * rhs.x + y * rhs.y;
}
double length() {
return sqrt(x * x + y * y);
}
Point unit() {
return *this / length();
}
void makeAg() {
ag = atan2(y, x);
}
void print() {
printf("%.10f %.10f\n", x, y);
}
};
typedef Point Vector; double dist(const Point &a, const Point &b) {
return (a - b).length();
} double cross(const Point &a, const Point &b) {
return a.x * b.y - a.y * b.x;
}
//ret >= 0 means turn right
double cross(const Point &sp, const Point &ed, const Point &op) {
return cross(sp - op, ed - op);
} double area(const Point& a, const Point &b, const Point &c) {
return fabs(cross(a - c, b - c)) / ;
}
//counter-clockwise
Point rotate(const Point &p, double angle, const Point &o = Point(, )) {
Point t = p - o;
double x = t.x * cos(angle) - t.y * sin(angle);
double y = t.y * cos(angle) + t.x * sin(angle);
return Point(x, y) + o;
} struct Seg {
Point st, ed;
double ag;
Seg() {}
Seg(Point st, Point ed): st(st), ed(ed) {}
void read() {
st.read(); ed.read();
}
void makeAg() {
ag = atan2(ed.y - st.y, ed.x - st.x);
}
};
typedef Seg Line; //ax + by + c > 0
Line buildLine(double a, double b, double c) {
if(sgn(a) == && sgn(b) == ) return Line(Point(sgn(c) > ? - : , INF), Point(, INF));
if(sgn(a) == ) return Line(Point(sgn(b), -c/b), Point(, -c/b));
if(sgn(b) == ) return Line(Point(-c/a, ), Point(-c/a, sgn(a)));
if(b < ) return Line(Point(, -c/b), Point(, -(a + c) / b));
else return Line(Point(, -(a + c) / b), Point(, -c/b));
} void moveRight(Line &v, double r) {
double dx = v.ed.x - v.st.x, dy = v.ed.y - v.st.y;
dx = dx / dist(v.st, v.ed) * r;
dy = dy / dist(v.st, v.ed) * r;
v.st.x += dy; v.ed.x += dy;
v.st.y -= dx; v.ed.y -= dx;
} bool isOnSeg(const Seg &s, const Point &p) {
return (p == s.st || p == s.ed) ||
(((p.x - s.st.x) * (p.x - s.ed.x) < ||
(p.y - s.st.y) * (p.y - s.ed.y) < ) &&
sgn(cross(s.ed, p, s.st) == ));
} bool isIntersected(const Point &s1, const Point &e1, const Point &s2, const Point &e2) {
return (max(s1.x, e1.x) >= min(s2.x, e2.x)) &&
(max(s2.x, e2.x) >= min(s1.x, e1.x)) &&
(max(s1.y, e1.y) >= min(s2.y, e2.y)) &&
(max(s2.y, e2.y) >= min(s1.y, e1.y)) &&
(cross(s2, e1, s1) * cross(e1, e2, s1) >= ) &&
(cross(s1, e2, s2) * cross(e2, e1, s2) >= );
} bool isIntersected(const Seg &a, const Seg &b) {
return isIntersected(a.st, a.ed, b.st, b.ed);
} bool isParallel(const Seg &a, const Seg &b) {
return sgn(cross(a.ed - a.st, b.ed - b.st)) == ;
} //return Ax + By + C =0 's A, B, C
void Coefficient(const Line &L, double &A, double &B, double &C) {
A = L.ed.y - L.st.y;
B = L.st.x - L.ed.x;
C = L.ed.x * L.st.y - L.st.x * L.ed.y;
}
//point of intersection
Point operator * (const Line &a, const Line &b) {
double A1, B1, C1;
double A2, B2, C2;
Coefficient(a, A1, B1, C1);
Coefficient(b, A2, B2, C2);
Point I;
I.x = - (B2 * C1 - B1 * C2) / (A1 * B2 - A2 * B1);
I.y = (A2 * C1 - A1 * C2) / (A1 * B2 - A2 * B1);
return I;
} bool isEqual(const Line &a, const Line &b) {
double A1, B1, C1;
double A2, B2, C2;
Coefficient(a, A1, B1, C1);
Coefficient(b, A2, B2, C2);
return sgn(A1 * B2 - A2 * B1) == && sgn(A1 * C2 - A2 * C1) == && sgn(B1 * C2 - B2 * C1) == ;
} double Point_to_Line(const Point &p, const Line &L) {
return fabs(cross(p, L.st, L.ed)/dist(L.st, L.ed));
} double Point_to_Seg(const Point &p, const Seg &L) {
if(sgn((L.ed - L.st) * (p - L.st)) < ) return dist(p, L.st);
if(sgn((L.st - L.ed) * (p - L.ed)) < ) return dist(p, L.ed);
return Point_to_Line(p, L);
} double Seg_to_Seg(const Seg &a, const Seg &b) {
double ans1 = min(Point_to_Seg(a.st, b), Point_to_Seg(a.ed, b));
double ans2 = min(Point_to_Seg(b.st, a), Point_to_Seg(b.ed, a));
return min(ans1, ans2);
} struct Poly {
int n;
Point p[MAXN];//p[n] = p[0]
void init(Point *pp, int nn) {
n = nn;
for(int i = ; i < n; ++i) p[i] = pp[i];
p[n] = p[];
}
double area() {
if(n < ) return ;
double s = p[].y * (p[n - ].x - p[].x);
for(int i = ; i < n; ++i)
s += p[i].y * (p[i - ].x - p[i + ].x);
return s / ;
}
};
//the convex hull is clockwise
void Graham_scan(Point *p, int n, int *stk, int &top) {//stk[0] = stk[top]
sort(p, p + n);
top = ;
stk[] = ; stk[] = ;
for(int i = ; i < n; ++i) {
while(top && cross(p[i], p[stk[top]], p[stk[top - ]]) <= ) --top;
stk[++top] = i;
}
int len = top;
stk[++top] = n - ;
for(int i = n - ; i >= ; --i) {
while(top != len && cross(p[i], p[stk[top]], p[stk[top - ]]) <= ) --top;
stk[++top] = i;
}
}
//use for half_planes_cross
bool cmpAg(const Line &a, const Line &b) {
if(sgn(a.ag - b.ag) == )
return sgn(cross(b.ed, a.st, b.st)) < ;
return a.ag < b.ag;
}
//clockwise, plane is on the right
bool half_planes_cross(Line *v, int vn, Poly &res, Line *deq) {
int i, n;
sort(v, v + vn, cmpAg);
for(i = n = ; i < vn; ++i) {
if(sgn(v[i].ag - v[i-].ag) == ) continue;
v[n++] = v[i];
}
int head = , tail = ;
deq[] = v[], deq[] = v[];
for(i = ; i < n; ++i) {
if(isParallel(deq[tail - ], deq[tail]) || isParallel(deq[head], deq[head + ]))
return false;
while(head < tail && sgn(cross(v[i].ed, deq[tail - ] * deq[tail], v[i].st)) > )
--tail;
while(head < tail && sgn(cross(v[i].ed, deq[head] * deq[head + ], v[i].st)) > )
++head;
deq[++tail] = v[i];
}
while(head < tail && sgn(cross(deq[head].ed, deq[tail - ] * deq[tail], deq[head].st)) > )
--tail;
while(head < tail && sgn(cross(deq[tail].ed, deq[head] * deq[head + ], deq[tail].st)) > )
++head;
if(tail <= head + ) return false;
res.n = ;
for(i = head; i < tail; ++i)
res.p[res.n++] = deq[i] * deq[i + ];
res.p[res.n++] = deq[head] * deq[tail];
res.n = unique(res.p, res.p + res.n) - res.p;
res.p[res.n] = res.p[];
return true;
} //ix and jx is the points whose distance is return, res.p[n - 1] = res.p[0], res must be clockwise
double dia_rotating_calipers(Poly &res, int &ix, int &jx) {
double dia = ;
int q = ;
for(int i = ; i < res.n - ; ++i) {
while(sgn(cross(res.p[i], res.p[q + ], res.p[i + ]) - cross(res.p[i], res.p[q], res.p[i + ])) > )
q = (q + ) % (res.n - );
if(sgn(dist(res.p[i], res.p[q]) - dia) > ) {
dia = dist(res.p[i], res.p[q]);
ix = i; jx = q;
}
if(sgn(dist(res.p[i + ], res.p[q]) - dia) > ) {
dia = dist(res.p[i + ], res.p[q]);
ix = i + ; jx = q;
}
}
return dia;
}
//a and b must be clockwise, find the minimum distance between two convex hull
double half_rotating_calipers(Poly &a, Poly &b) {
int sa = , sb = ;
for(int i = ; i < a.n; ++i) if(sgn(a.p[i].y - a.p[sa].y) < ) sa = i;
for(int i = ; i < b.n; ++i) if(sgn(b.p[i].y - b.p[sb].y) < ) sb = i;
double tmp, ans = dist(a.p[], b.p[]);
for(int i = ; i < a.n; ++i) {
while(sgn(tmp = cross(a.p[sa], a.p[sa + ], b.p[sb + ]) - cross(a.p[sa], a.p[sa + ], b.p[sb])) > )
sb = (sb + ) % (b.n - );
if(sgn(tmp) < ) ans = min(ans, Point_to_Seg(b.p[sb], Seg(a.p[sa], a.p[sa + ])));
else ans = min(ans, Seg_to_Seg(Seg(a.p[sa], a.p[sa + ]), Seg(b.p[sb], b.p[sb + ])));
sa = (sa + ) % (a.n - );
}
return ans;
} double rotating_calipers(Poly &a, Poly &b) {
return min(half_rotating_calipers(a, b), half_rotating_calipers(b, a));
} /*******************************************************************************************/ Poly a, b; double solve() {
double ans = 1e100;
for(int i = ; i < a.n; ++i)
for(int j = ; j < b.n; ++j) ans = min(ans, dist(a.p[i], b.p[j]));
return ans;
} int main() {
while(scanf("%d%d", &a.n, &b.n) != EOF) {
if(a.n == && b.n == ) break;
for(int i = ; i < a.n; ++i) a.p[i].read();
a.p[a.n++] = a.p[];
for(int i = ; i < b.n; ++i) b.p[i].read();
b.p[b.n++] = b.p[];
printf("%f\n", rotating_calipers(a, b));
//printf("%f\n", solve());
}
return ;
}
POJ 3608 Bridge Across Islands(计算几何の旋转卡壳)的更多相关文章
- POJ 3608 Bridge Across Islands(旋转卡壳,两凸包最短距离)
Bridge Across Islands Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 7202 Accepted: ...
- POJ 3608 Bridge Across Islands (旋转卡壳)
[题目链接] http://poj.org/problem?id=3608 [题目大意] 求出两个凸包之间的最短距离 [题解] 我们先找到一个凸包的上顶点和一个凸包的下定点,以这两个点为起点向下一个点 ...
- POJ - 3608 Bridge Across Islands【旋转卡壳】及一些有趣现象
给两个凸包,求这两个凸包间最短距离 旋转卡壳的基础题 因为是初学旋转卡壳,所以找了别人的代码进行观摩..然而发现很有意思的现象 比如说这个代码(只截取了关键部分) double solve(Point ...
- POJ 3608 Bridge Across Islands --凸包间距离,旋转卡壳
题意: 给你两个凸包,求其最短距离. 解法: POJ 我真的是弄不懂了,也不说一声点就是按顺时针给出的,不用调整点顺序. 还是说数据水了,没出乱给点或给逆时针点的数据呢..我直接默认顺时针给的点居然A ...
- POJ 3608 Bridge Across Islands [旋转卡壳]
Bridge Across Islands Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 10455 Accepted: ...
- ●POJ 3608 Bridge Across Islands
题链: http://poj.org/problem?id=3608 题解: 计算几何,求两个凸包间的最小距离,旋转卡壳 两个凸包间的距离,无非下面三种情况: 所以可以基于旋转卡壳的思想,去求最小距离 ...
- POJ 3608 凸包间最短距离(旋转卡壳)
Bridge Across Islands Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 11539 Accepted: ...
- 「POJ-3608」Bridge Across Islands (旋转卡壳--求两凸包距离)
题目链接 POJ-3608 Bridge Across Islands 题意 依次按逆时针方向给出凸包,在两个凸包小岛之间造桥,求最小距离. 题解 旋转卡壳的应用之一:求两凸包的最近距离. 找到凸包 ...
- poj 3608 Bridge Across Islands
题目:计算两个不相交凸多边形间的最小距离. 分析:计算几何.凸包.旋转卡壳.分别求出凸包,利用旋转卡壳求出对踵点对,枚举距离即可. 注意:1.利用向量法判断旋转,而不是计算角度:避免精度问题和TLE. ...
随机推荐
- CF1066EBinary Numbers AND Sum(前缀和,二进制)
题目大意 现在,给你两个位数为 n 和 m 的两个二进制数a,b,现在,我们要进行如下操作: 计算a&b 答案累加上一个操作的值 bbb右移一位,最后一位直接舍弃 现在,请你算出最终的答案,并 ...
- 【C++ Primer】读书笔记_第一章
Main(): 1. C++程序必须包含main()函数,操作系统通过调用main来运行C++程序. 2. main()的形参可以为空. 3. main函数的返回类型必须为int,返回给操作系统.in ...
- Linux 运维工程师学习成长路线上要经历哪四个阶段?
之前曾看到一篇新闻,Linux之父建议大家找一份基于Linux和开源环境的工作.今天就来聊一聊我的想法,本人8年Linux运维一线经验,呆过很多互联网公司,从一线运维做到运维架构师一职,也见证了中国运 ...
- sort的用法
早一段时间一直没有理解sort的用法,在早几天终于是研究的明白的,所以就来分享一下,如果你也被这个方法困扰,没懂原理,可以看一下这遍文章,希望有所帮助. 第一种,最简单的排序,纯数字排序: var a ...
- 常用EL函数汇总 fn:contains ,fn:substring,fn:substringAfter...
由于在JSP页面中显示数据时,经常需要对显示的字符串进行处理,SUN公司针对于一些常见处理定义了一套EL函数库供开发者使用.这些EL函数在JSTL开发包中进行描述,因此在JSP页面中使用SUN公司的E ...
- 使用Scala开发Apache Kafka的TOP 20大好用实践
本文作者是一位软件工程师,他对20位开发人员和数据科学家使用Apache Kafka的方式进行了最大限度得深入研究,最终将生产实践环节需要注意的问题总结为本文所列的20条建议. Apache Kafk ...
- LCD触屏驱动
tiny4412多点触摸屏驱动程序(基于I2C协议): #include <linux/kernel.h> #include <linux/module.h> #include ...
- fedora19之后的版本安装mysql
正准备学习linux平台的mysql,却发现在fedora21平台下安装mysql总是失败,查了些资料,总结如下: 错误示范: 按照安装软件的经验,习惯性输入以下的命令: $sudo dnf inst ...
- LeetCode: 53. Maximum Subarray(Easy)
1. 原题链接 https://leetcode.com/problems/maximum-subarray/discuss/ 2. 题目要求 给定一个整型数组,返回其子串之和的最大值 例如,[-2, ...
- (转)EDM邮件制作规范完整版
转载:http://www.maildesign.cn/archives/1380 在我们的日常工作中,经常需要发送邮件和我们的会员沟通.如注册确认.营销推广等.这些由站方发给会员的信件,往往纯文本格 ...