求两个凸包间的最短距离。
大部分都是抄的小岛前辈的模板。
真是无私奉献的典范啊!应有尽有,巨细靡遗。。
顺便连带整理了一下自己的。(感觉自己的模板也写得变紧凑了。。)
#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; }