求两个凸包间的最短距离。
大部分都是抄的小岛前辈的模板。
真是无私奉献的典范啊!应有尽有,巨细靡遗。。
顺便连带整理了一下自己的。(感觉自己的模板也写得变紧凑了。。)
#include <algorithm>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <stdio.h>
#include <math.h>
using namespace std;
#define MAXN 10010
#define eps 1e-10
//const double pi = acos(-1.0);
inline double sig(double x) { return (x > eps) - (x < -eps); };
template <class T> inline T sqr(T a) { return a * a; }
struct Point
{
double x, y;
Point() {}
Point(double _x, double _y): x(_x), y(_y) {}
void in();
void out() const;
double len() const;
double len2() const;
double dis(const Point &argu) const;
double dis2(const Point &argu) const;
bool operator <(const Point &argu) const;
Point operator -(const Point &argu) const;
double operator ^(const Point &argu) const;
double operator *(const Point &argu) const;
};
struct Segment
{
Point a, b;
Segment() {}
Segment(Point _a, Point _b): a(_a), b(_b) {}
void in();
Point d() const;
void out() const;
double len() const;
double len2() const;
int sgn(const Segment &argu) const;
bool qrt(const Segment &argu) const;
double dis2(const Point &argu) const;
double dis2(const Segment &argu) const;
};
struct Line
{
Segment l;
Line() {}
Line(Segment _l): l(_l) {}
double dis2(const Point &argu) const;
double dis2(const Segment &argu) const;
};
inline double Cross(const Point &o, const Point &a, const Point &b) { return (a - o) ^ (b - o); }
void Point::in() { scanf("%lf%lf", &x, &y); }
double Point::len() const { return sqrt(len2()); }
double Point::len2() const { return x * x + y * y; }
void Point::out() const{ printf("%.0lf %.0lf\n", x, y); }
double Point::dis(const Point &argu) const { return sqrt(dis2(argu)); }
double Point::operator ^(const Point &argu) const { return x * argu.y - y * argu.x; }
double Point::operator *(const Point &argu) const { return x * argu.x + y * argu.y; }
Point Point::operator -(const Point &argu) const { return Point(x - argu.x, y - argu.y); }
bool Point::operator <(const Point &argu) const { return sig(x - argu.x) == 0 ? y < argu.y : x < argu.x; }
double Point::dis2(const Point &argu) const { return (x - argu.x) * (x - argu.x) + (y - argu.y) * (y - argu.y); }
void Segment::in() { a.in(), b.in(); }
Point Segment::d() const { return b - a; }
double Segment::len2() const { return d().len2(); }
double Segment::len() const { return sqrt(len2()); }
void Segment::out() const { a.out(), b.out(); }
double Segment::dis2(const Segment &argu) const
{
if(~sgn(argu)) return 0;
return min(min(dis2(argu.a), dis2(argu.b)), min(argu.dis2(a), argu.dis2(b)));
}
double Segment::dis2(const Point &argu) const
{
Point pa = argu - a, pb = argu - b;
if(sig(d() * pa) <= 0) return pa.len2(); if(sig(d() * pb) >= 0) return pb.len2();
Line l = Line((*this)); return l.dis2(argu);
}
int Segment::sgn(const Segment &argu) const
{
if(!qrt(argu)) return -1;
return sig(Cross(a, b, argu.a)) * sig(Cross(a, b, argu.b)) <= 0 &&
sig(Cross(argu.a, argu.b, a)) * sig(Cross(argu.a, argu.b, b)) <= 0 ? 1 : -1;
}
//快速排斥实验
bool Segment::qrt(const Segment &argu) const
{
return min(a.x, b.x) <= max(argu.a.x, argu.b.x) && min(a.y, b.y) <= max(argu.a.y, argu.b.y) &&
min(argu.a.x, argu.b.x) <= max(a.x, b.x) && min(argu.a.y, argu.b.y) <= max(a.y, b.y);
}
double Line::dis2(const Point &argu) const { return sqr(fabs(l.d() ^ (argu - l.a))) / l.len2(); }
double Line::dis2(const Segment &argu) const
{
Point v1 = argu.a - l.a, v2 = argu.b - l.b; double d1 = l.d() ^ v1, d2 = l.d() ^ v2;
return sig(d1) != sig(d2) ? 0 : sqr(min(fabs(d1), fabs(d2))) / l.len2();
}
int ConvexHull(Point p[], Point ch[], int n)
{
sort(p, p + n);
int top = 0;
for(int i = 0; i < n; i++)
{
while(top > 1 && Cross(ch[top - 2], ch[top - 1], p[i]) <= 0) top--;
ch[top++] = p[i];
}
int t = top;
for(int i = n - 2; i >= 0; i--)
{
while(top > t && Cross(ch[top - 2], ch[top - 1], p[i]) <= 0) top--;
ch[top++] = p[i];
}
top--;
return top;
}
double RotatingCalipers(Point p1[], int n1, Point p2[], int n2)
{
double ret = 1e15;
int t = 0, t1 = 1, t2 = 1;
for(int i = 0; i < n1; i++) if(p1[i].y > p1[t1].y) t1 = i;
for(int i = 0; i < n2; i++) if(p2[i].y < p2[t1].y) t1 = i;
for(int i = 0; i < n1; i++)
{
while(sig((p1[t1 + 1] - p1[t1]) ^ (p2[t2 + 1] - p2[t2])) > 0) t2 = (t2 + 1) % n2;
Segment s1 = Segment(p1[t1], p1[t1 + 1]);
Segment s2 = Segment(p2[t2], p2[t2 + 1]);
ret = min(ret, s1.dis2(s2));
t1 = (t1 + 1) % n1;
}
return ret;
}
Point p1[MAXN], ch1[MAXN];
Point p2[MAXN], ch2[MAXN];
int n1, n2, c1, c2;
void solve()
{
c1 = ConvexHull(p1, ch1, n1); ch1[c1] = ch1[0];
c2 = ConvexHull(p2, ch2, n2); ch2[c2] = ch2[0];
double d1 = RotatingCalipers(ch1, c1, ch2, c2);
double d2 = RotatingCalipers(ch2, c2, ch1, c1);
printf("%.5lf\n", sqrt(min(d1, d2)));
}
int main()
{
// freopen("3608.in", "r", stdin);
while(scanf("%d%d", &n1, &n2) && (n1 || n2))
{
for(int i = 0; i < n1; i++) p1[i].in();
for(int i = 0; i < n2; i++) p2[i].in();
solve();
}
return 0;
}