http://acm.hdu.edu.cn/showproblem.php?pid=2823
应该是经典的凸包间最短距离的题目吧。印象中是用旋转卡壳来过的,不过我在hdu水了一下,一个暴力O(n^2)算法直接撸过。
我的做法很简单,就是先判断两个凸包是否相交或包含,然后就用点到线段距离枚举凸包间距离,加了一个遇到距离增加的时候剪枝就过了。
代码如下:
1 #include <cstdio> 2 #include <cstring> 3 #include <cmath> 4 #include <vector> 5 #include <algorithm> 6 #include <iostream> 7 8 using namespace std; 9 10 struct Point { 11 double x, y; 12 Point() { x = y = 0.0;} 13 Point(double x, double y) : x(x), y(y) {} 14 } ; 15 template <class T> T sqr(T x) { return x * x;} 16 inline double ptDis(Point a, Point b) { return sqrt(sqr(a.x - b.x) + sqr(a.y - b.y));} 17 18 typedef Point Vec; 19 Vec operator + (Vec a, Vec b) { return Vec(a.x + b.x, a.y + b.y);} 20 Vec operator - (Vec a, Vec b) { return Vec(a.x - b.x, a.y - b.y);} 21 Vec operator * (Vec a, double p) { return Vec(a.x * p, a.y * p);} 22 Vec operator / (Vec a, double p) { return Vec(a.x / p, a.y / p);} 23 24 const double EPS = 1e-8; 25 const double PI = acos(-1.0); 26 inline int sgn(double x) { return fabs(x) < EPS ? 0 : (x < 0 ? -1 : 1);} 27 bool operator < (Point a, Point b) { return a.x < b.x || a.x == b.x && a.y < b.y;} 28 bool operator == (Point a, Point b) { return !sgn(a.x - b.x) && !sgn(a.y - b.y);} 29 30 inline double dotDet(Vec a, Vec b) { return a.x * b.x + a.y * b.y;} 31 inline double crossDet(Vec a, Vec b) { return a.x * b.y - a.y * b.x;} 32 inline double crossDet(Point o, Point a, Point b) { return crossDet(a - o, b - o);} 33 inline double vecLen(Vec x) { return sqrt(dotDet(x, x));} 34 35 struct Line { 36 Point s, t; 37 Line() {} 38 Line(Point s, Point t) : s(s), t(t) {} 39 } ; 40 41 inline int onSeg(Point x, Point a, Point b) { return sgn(crossDet(x, a, b)) == 0 && sgn(dotDet(a - x, b - x)) < 0;} 42 43 int segIntersect(Point a, Point c, Point b, Point d) { 44 Vec v1 = b - a, v2 = c - b, v3 = d - c, v4 = a - d; 45 int a_bc = sgn(crossDet(v1, v2)); 46 int b_cd = sgn(crossDet(v2, v3)); 47 int c_da = sgn(crossDet(v3, v4)); 48 int d_ab = sgn(crossDet(v4, v1)); 49 if (a_bc * c_da > 0 && b_cd * d_ab > 0) return 1; 50 if (onSeg(b, a, c) && c_da) return 2; 51 if (onSeg(c, b, d) && d_ab) return 2; 52 if (onSeg(d, c, a) && a_bc) return 2; 53 if (onSeg(a, d, b) && b_cd) return 2; 54 return 0; 55 } 56 57 int andrew(Point *pt, int n, Point *ch) { 58 // cout << "sort!!" << n << endl; 59 sort(pt, pt + n); 60 int m = 0; 61 // cout << "here??" << endl; 62 for (int i = 0; i < n; i++) { 63 while (m > 1 && crossDet(ch[m - 2], ch[m - 1], pt[i]) <= 0) m--; 64 ch[m++] = pt[i]; 65 } 66 int k = m; 67 for (int i = n - 2; i >= 0; i--) { 68 while (m > k && crossDet(ch[m - 2], ch[m - 1], pt[i]) <= 0) m--; 69 ch[m++] = pt[i]; 70 } 71 if (n > 1) m--; 72 return m; 73 } 74 75 int ptInPoly(Point p, Point *poly, int n) { 76 int wn = 0; 77 poly[n] = poly[0]; 78 for (int i = 0; i < n; i++) { 79 if (onSeg(p, poly[i], poly[i + 1])) return -1; 80 int k = sgn(crossDet(poly[i], poly[i + 1], p)); 81 int d1 = sgn(poly[i].y - p.y); 82 int d2 = sgn(poly[i + 1].y - p.y); 83 if (k > 0 && d1 <= 0 && d2 > 0) wn++; 84 if (k < 0 && d2 <= 0 && d1 > 0) wn--; 85 } 86 if (wn != 0) return 1; 87 return 0; 88 } 89 90 const int N = 1111; 91 Point pt[2][N], ch[2][N]; 92 93 bool polyApart(Point *a, int n, Point *b, int m) { 94 a[n] = a[0], b[m] = b[0]; 95 for (int i = 0; i < n; i++) if (ptInPoly(a[i], b, m)) return false; 96 for (int i = 0; i < m; i++) if (ptInPoly(b[i], a, n)) return false; 97 for (int i = 0; i < n; i++) { 98 for (int j = 0; j < m; j++) { 99 if (segIntersect(a[i], a[i + 1], b[j], b[j + 1])) return false; 100 } 101 } 102 return true; 103 } 104 105 double pt2Line(Point x, Point a, Point b) { 106 Vec v1 = b - a, v2 = x - a; 107 return crossDet(v1, v2) / vecLen(v1); 108 } 109 110 double pt2Seg(Point x, Point a, Point b) { 111 if (a == b) return vecLen(x - a); 112 Vec v1 = b - a, v2 = x - a, v3 = x - b; 113 if (sgn(dotDet(v1, v2)) < 0) return vecLen(v2); 114 if (sgn(dotDet(v1, v3)) > 0) return vecLen(v3); 115 return fabs(crossDet(v1, v2)) / vecLen(v1); 116 } 117 118 const double FINF = 1e100; 119 120 double polyDis(Point *a, int n, Point *b, int m) { 121 if (!polyApart(a, n, b, m)) return 0.0; 122 a[n] = a[0], b[m] = b[0]; 123 double mini = FINF; 124 for (int i = 0; i < n; i++) { 125 double last, cur; 126 for (int j = 0; j < m; j++) { 127 cur = pt2Seg(b[j], a[i], a[i + 1]); 128 mini = min(mini, cur); 129 if (j && last < cur) break; 130 last = cur; 131 } 132 } 133 for (int i = 0; i < m; i++) { 134 double last, cur; 135 for (int j = 0; j < n; j++) { 136 cur = pt2Seg(a[j], b[i], b[i + 1]); 137 mini = min(mini, cur); 138 if (j && last < cur) break; 139 last = cur; 140 } 141 } 142 return mini; 143 } 144 145 int main() { 146 // freopen("in", "r", stdin); 147 int n[2]; 148 while (~scanf("%d%d", &n[0], &n[1])) { 149 for (int i = 0; i < 2; i++) { 150 for (int j = 0; j < n[i]; j++) { 151 scanf("%lf%lf", &pt[i][j].x, &pt[i][j].y); 152 } 153 n[i] = andrew(pt[i], n[i], ch[i]); 154 } 155 printf("%.4f\n", polyDis(ch[0], n[0], ch[1], n[1])); 156 } 157 return 0; 158 }
——written by Lyon