original link - http://poj.org/problem?id=3608
题意:
给出两个顺时针排序好的凸包,求这两个凸包的最近点对距离。
解析:
旋转卡壳的另外一个应用。
先找出P1P1P1中的最低点,P2P2P2中的最高点,然后旋转(顺时针逆时针随意,要保证两个切线旋转方向相同)。
每次P1P1P1的切线旋转到与一条边重合,找出P2P2P2中离这条切线最近的点
1. 如果只有一个点,那么就是点到线的距离
2. 否则就是两条边4个点的最近距离
显然这样会漏掉情况,所以要对P2P2P2也做一遍。
代码:
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
#include<time.h>
using namespace std;
const int maxn = 5e4 + 9;
const double eps = 1e-7;
struct point {
double x, y;
point(double x = 0, double y = 0): x(x), y(y) {}
};
typedef point P;
typedef point Point;
typedef point Vector;
Vector operator + (Vector a, Vector b) { //向量加法
return Vector(a.x + b.x, a.y + b.y);
}
Vector operator - (Vector a, Vector b) { //向量减法
return Vector(a.x - b.x, a.y - b.y);
}
Vector operator * (Vector a, double p) { //向量数乘
return Vector(a.x * p, a.y * p);
}
Vector operator / (Vector a, double p) { //向量数除
return Vector(a.x / p, a.y / p);
}
int dcmp(double x) { //精度三态函数(>0,<0,=0)
if (fabs(x) < eps)
return 0;
else if (x > 0)
return 1;
return -1;
}
bool operator == (const Point &a, const Point &b) { //向量相等
return dcmp(a.x - b.x) == 0 && dcmp(a.y - b.y) == 0;
}
double Cross(P a, P b) { // 叉积 平行四边形面积
return (a.x * b.y) - (b.x * a.y);
}
double Dot(P a, P b) {
return a.x * b.x + a.y * b.y;
}
double Length(Vector v) {
return sqrt(v.x * v.x + v.y * v.y);
}
double Distance(P a, P b) {
return sqrt(Length(a - b));
}
point p1[maxn], p2[maxn];
int n1, n2;
#define rep(i,a,b) for(int i=a;i<=b;i++)
double DistanceToSeg(Point P, Point A, Point B) {
if(A == B)
return Length(P - A);
Vector v1 = B - A, v2 = P - A, v3 = P - B;
if(dcmp(Dot(v1, v2)) < 0)
return Length(v2);
if(dcmp(Dot(v1, v3)) > 0)
return Length(v3);
return fabs(Cross(v1, v2)) / Length(v1);
}
double SegDistancetoSeg(Point A, Point B, Point C, Point D) {
return min(min(DistanceToSeg(C, A, B), DistanceToSeg(D, A, B)),
min(DistanceToSeg(A, C, D), DistanceToSeg(B, C, D)));
}
double RotateCalipers(P *p1, int n1, P *p2, int n2) {
int q1 = 1, q2 = 1; // q1 ymin, q2 ymax
rep(i, 2, n1)
if(p1[i].y < p1[q1].y)
q1 = i;
rep(i, 2, n2)
if(p2[i].y > p2[q2].y)
q2 = i;
double ans = 1e18, tmp;
p1[n1 + 1] = p1[1], p2[n2 + 1] = p2[1];
rep(i, 1, n1) {
while(dcmp(tmp = Cross(p1[q1 + 1] - p1[q1], p2[q2 + 1] - p1[q1]) -
Cross(p1[q1 + 1] - p1[q1], p2[q2] - p1[q1])) > 0)
q2 = q2 % n2 + 1;
if(dcmp(tmp) < 0)
ans = min(ans,
DistanceToSeg(p2[q2], p1[q1], p1[q1 + 1]));
else
ans = min(ans,
SegDistancetoSeg(p1[q1], p1[q1 + 1], p2[q2], p2[q2 + 1]));
q1 = q1 % n1 + 1;
}
return ans;
}
int main() {
while(scanf("%d%d", &n1, &n2), n1 + n2) {
rep(i, 1, n1)
scanf("%lf%lf", &p1[i].x, &p1[i].y);
rep(i, 1, n2)
scanf("%lf%lf", &p2[i].x, &p2[i].y);
printf("%.5f\n", min(RotateCalipers(p1, n1, p2, n2),
RotateCalipers(p2, n2, p1, n1)));
}
}