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. ...
随机推荐
- struts2-笔记
文件下载http://struts.apache.org/download.cgi 第一步导入jar 包 在lib中有jar 包,不能把这些都导入到项目中 在apps 目录里面,找到实例程序,程序中直 ...
- SpringBoot整合Eureka搭建微服务
1.创建一个services项目,添加三个子模块client(客户端).service(服务端).registry(注册中心) 1.1 创建一个services项目 1.2 添加pom.xml依赖 & ...
- Linux中JDK的安装步骤
1.下载jdk安装包rpm格式安装 http://download.oracle.com/otn-pub/java/jdk/8u131-b11/d54c1d3a095b4ff2b6607d096fa8 ...
- Js 手指事件
1.Touch事件简介 pc上的web页面鼠标会产生onmousedown.onmouseup.onmouseout.onmouseover.onmousemove的事件,但是在移动终端如ipho ...
- hive 学习系列六 hive 去重办法的思考
方法1,建立临时表,利用hive的collect_set 进行去重. create table if not exists tubutest ( name1 string, name2 string ...
- Vue directive自定义指令+canvas实现H5图片压缩上传-Base64格式
前言 最近优化项目-手机拍照图片太大,回显速度比较慢,使用了vue的自定义指令实现H5压缩上传base64格式的图片 canvas自定义指令 Vue.directive("canvas&qu ...
- 解决 Node.js 错误 Error:listen EADDRINUSE
第一次尝试 node.js 中的 express 框架,写了第一个 js 文件之后,在 WebStorm 运行,到游览器刷新,成功运行. 又创建一个 js 文件,写的是静态路由的访问,结果出现了 Er ...
- VMWare共享文件
windows与虚拟机的linux共享windows下的一个文件夹 1.重新安装VMware Tools,在VMware面板上选择“虚拟机-重新安装VMware tools…” 2.使用命令 Ctrl ...
- python3 urllib爬取wallhalla网站图片
点我去我的github上看源码 简单使用静态方法爬取https://wallhalla.com/网站的图片 参考: https://blog.csdn.net/cquptcmj/article/det ...
- STM32 USB设备描述符、配置描述符、端点描述符含义
查了一整天的资料,自己把不懂的全部试了一遍 一下是程序以及注释 /* USB设备描述符*/ const uint8_t CustomHID_DeviceDescriptor[CUSTOMHID_SIZ ...