POJ 2187 Beauty Contest(凸包+旋转卡壳)
Description
Bessie, Farmer John's prize cow, has just won first place in a bovine beauty contest, earning the title 'Miss Cow World'. As a result, Bessie will make a tour of N (2 <= N <= 50,000) farms around the world in order to spread goodwill between farmers and their cows. For simplicity, the world will be represented as a two-dimensional plane, where each farm is located at a pair of integer coordinates (x,y), each having a value in the range -10,000 ... 10,000. No two farms share the same pair of coordinates.
Even though Bessie travels directly in a straight line between pairs of farms, the distance between some farms can be quite large, so she wants to bring a suitcase full of hay with her so she has enough food to eat on each leg of her journey. Since Bessie refills her suitcase at every farm she visits, she wants to determine the maximum possible distance she might need to travel so she knows the size of suitcase she must bring.Help Bessie by computing the maximum distance among all pairs of farms.
Even though Bessie travels directly in a straight line between pairs of farms, the distance between some farms can be quite large, so she wants to bring a suitcase full of hay with her so she has enough food to eat on each leg of her journey. Since Bessie refills her suitcase at every farm she visits, she wants to determine the maximum possible distance she might need to travel so she knows the size of suitcase she must bring.Help Bessie by computing the maximum distance among all pairs of farms.
Input
* Line 1: A single integer, N
* Lines 2..N+1: Two space-separated integers x and y specifying coordinate of each farm
* Lines 2..N+1: Two space-separated integers x and y specifying coordinate of each farm
Output
* Line 1: A single integer that is the squared distance between the pair of farms that are farthest apart from each other.
题目大意:给一堆点,求最远点距离的平方。
思路:先求个凸包,再用旋转卡壳求最远点对(这题数据出得不好,凸包之后暴力求最远点对)
代码(188MS):
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #include <cmath> 6 using namespace std; 7 8 const int MAXN = 50010; 9 const double EPS = 1e-10; 10 const double PI = acos(-1.0);//3.14159265358979323846 11 const double INF = 1; 12 13 inline int sgn(double x) { 14 return (x > EPS) - (x < -EPS); 15 } 16 17 struct Point { 18 double x, y, ag; 19 Point() {} 20 Point(double x, double y): x(x), y(y) {} 21 void read() { 22 scanf("%lf%lf", &x, &y); 23 } 24 bool operator == (const Point &rhs) const { 25 return sgn(x - rhs.x) == 0 && sgn(y - rhs.y) == 0; 26 } 27 bool operator < (const Point &rhs) const { 28 if(y != rhs.y) return y < rhs.y; 29 return x < rhs.x; 30 } 31 Point operator + (const Point &rhs) const { 32 return Point(x + rhs.x, y + rhs.y); 33 } 34 Point operator - (const Point &rhs) const { 35 return Point(x - rhs.x, y - rhs.y); 36 } 37 Point operator * (const double &b) const { 38 return Point(x * b, y * b); 39 } 40 Point operator / (const double &b) const { 41 return Point(x / b, y / b); 42 } 43 double length() { 44 return sqrt(x * x + y * y); 45 } 46 Point unit() { 47 return *this / length(); 48 } 49 void makeAg() { 50 ag = atan2(y, x); 51 } 52 void print() { 53 printf("%.10f %.10f\n", x, y); 54 } 55 }; 56 typedef Point Vector; 57 58 double dist(const Point &a, const Point &b) { 59 return (a - b).length(); 60 } 61 62 double cross(const Point &a, const Point &b) { 63 return a.x * b.y - a.y * b.x; 64 } 65 //ret >= 0 means turn left 66 double cross(const Point &sp, const Point &ed, const Point &op) { 67 return sgn(cross(sp - op, ed - op)); 68 } 69 70 double area(const Point& a, const Point &b, const Point &c) { 71 return fabs(cross(a - c, b - c)) / 2; 72 } 73 //counter-clockwise 74 Point rotate(const Point &p, double angle, const Point &o = Point(0, 0)) { 75 Point t = p - o; 76 double x = t.x * cos(angle) - t.y * sin(angle); 77 double y = t.y * cos(angle) + t.x * sin(angle); 78 return Point(x, y) + o; 79 } 80 81 struct Seg { 82 Point st, ed; 83 double ag; 84 Seg() {} 85 Seg(Point st, Point ed): st(st), ed(ed) {} 86 void read() { 87 st.read(); ed.read(); 88 } 89 void makeAg() { 90 ag = atan2(ed.y - st.y, ed.x - st.x); 91 } 92 }; 93 typedef Seg Line; 94 95 //ax + by + c > 0 96 Line buildLine(double a, double b, double c) { 97 if(sgn(a) == 0 && sgn(b) == 0) return Line(Point(sgn(c) > 0 ? -1 : 1, INF), Point(0, INF)); 98 if(sgn(a) == 0) return Line(Point(sgn(b), -c/b), Point(0, -c/b)); 99 if(sgn(b) == 0) return Line(Point(-c/a, 0), Point(-c/a, sgn(a))); 100 if(b < 0) return Line(Point(0, -c/b), Point(1, -(a + c) / b)); 101 else return Line(Point(1, -(a + c) / b), Point(0, -c/b)); 102 } 103 104 void moveRight(Line &v, double r) { 105 double dx = v.ed.x - v.st.x, dy = v.ed.y - v.st.y; 106 dx = dx / dist(v.st, v.ed) * r; 107 dy = dy / dist(v.st, v.ed) * r; 108 v.st.x += dy; v.ed.x += dy; 109 v.st.y -= dx; v.ed.y -= dx; 110 } 111 112 bool isOnSeg(const Seg &s, const Point &p) { 113 return (p == s.st || p == s.ed) || 114 (((p.x - s.st.x) * (p.x - s.ed.x) < 0 || 115 (p.y - s.st.y) * (p.y - s.ed.y) < 0) && 116 sgn(cross(s.ed, p, s.st) == 0)); 117 } 118 119 bool isIntersected(const Point &s1, const Point &e1, const Point &s2, const Point &e2) { 120 return (max(s1.x, e1.x) >= min(s2.x, e2.x)) && 121 (max(s2.x, e2.x) >= min(s1.x, e1.x)) && 122 (max(s1.y, e1.y) >= min(s2.y, e2.y)) && 123 (max(s2.y, e2.y) >= min(s1.y, e1.y)) && 124 (cross(s2, e1, s1) * cross(e1, e2, s1) >= 0) && 125 (cross(s1, e2, s2) * cross(e2, e1, s2) >= 0); 126 } 127 128 bool isIntersected(const Seg &a, const Seg &b) { 129 return isIntersected(a.st, a.ed, b.st, b.ed); 130 } 131 132 bool isParallel(const Seg &a, const Seg &b) { 133 return sgn(cross(a.ed - a.st, b.ed - b.st)) == 0; 134 } 135 136 //return Ax + By + C =0 's A, B, C 137 void Coefficient(const Line &L, double &A, double &B, double &C) { 138 A = L.ed.y - L.st.y; 139 B = L.st.x - L.ed.x; 140 C = L.ed.x * L.st.y - L.st.x * L.ed.y; 141 } 142 //point of intersection 143 Point operator * (const Line &a, const Line &b) { 144 double A1, B1, C1; 145 double A2, B2, C2; 146 Coefficient(a, A1, B1, C1); 147 Coefficient(b, A2, B2, C2); 148 Point I; 149 I.x = - (B2 * C1 - B1 * C2) / (A1 * B2 - A2 * B1); 150 I.y = (A2 * C1 - A1 * C2) / (A1 * B2 - A2 * B1); 151 return I; 152 } 153 154 bool isEqual(const Line &a, const Line &b) { 155 double A1, B1, C1; 156 double A2, B2, C2; 157 Coefficient(a, A1, B1, C1); 158 Coefficient(b, A2, B2, C2); 159 return sgn(A1 * B2 - A2 * B1) == 0 && sgn(A1 * C2 - A2 * C1) == 0 && sgn(B1 * C2 - B2 * C1) == 0; 160 } 161 162 struct Poly { 163 int n; 164 Point p[MAXN];//p[n] = p[0] 165 void init(Point *pp, int nn) { 166 n = nn; 167 for(int i = 0; i < n; ++i) p[i] = pp[i]; 168 p[n] = p[0]; 169 } 170 double area() { 171 if(n < 3) return 0; 172 double s = p[0].y * (p[n - 1].x - p[1].x); 173 for(int i = 1; i < n; ++i) 174 s += p[i].y * (p[i - 1].x - p[i + 1].x); 175 return s / 2; 176 } 177 }; 178 179 void Graham_scan(Point *p, int n, int *stk, int &top) {//stk[0] = stk[top] 180 sort(p, p + n); 181 top = 1; 182 stk[0] = 0; stk[1] = 1; 183 for(int i = 2; i < n; ++i) { 184 while(top && cross(p[i], p[stk[top]], p[stk[top - 1]]) >= 0) --top; 185 stk[++top] = i; 186 } 187 int len = top; 188 stk[++top] = n - 2; 189 for(int i = n - 3; i >= 0; --i) { 190 while(top != len && cross(p[i], p[stk[top]], p[stk[top - 1]]) >= 0) --top; 191 stk[++top] = i; 192 } 193 } 194 //use for half_planes_cross 195 bool cmpAg(const Line &a, const Line &b) { 196 if(sgn(a.ag - b.ag) == 0) 197 return sgn(cross(b.ed, a.st, b.st)) < 0; 198 return a.ag < b.ag; 199 } 200 //clockwise, plane is on the right 201 bool half_planes_cross(Line *v, int vn, Poly &res, Line *deq) { 202 int i, n; 203 sort(v, v + vn, cmpAg); 204 for(i = n = 1; i < vn; ++i) { 205 if(sgn(v[i].ag - v[i-1].ag) == 0) continue; 206 v[n++] = v[i]; 207 } 208 int head = 0, tail = 1; 209 deq[0] = v[0], deq[1] = v[1]; 210 for(i = 2; i < n; ++i) { 211 if(isParallel(deq[tail - 1], deq[tail]) || isParallel(deq[head], deq[head + 1])) 212 return false; 213 while(head < tail && sgn(cross(v[i].ed, deq[tail - 1] * deq[tail], v[i].st)) > 0) 214 --tail; 215 while(head < tail && sgn(cross(v[i].ed, deq[head] * deq[head + 1], v[i].st)) > 0) 216 ++head; 217 deq[++tail] = v[i]; 218 } 219 while(head < tail && sgn(cross(deq[head].ed, deq[tail - 1] * deq[tail], deq[head].st)) > 0) 220 --tail; 221 while(head < tail && sgn(cross(deq[tail].ed, deq[head] * deq[head + 1], deq[tail].st)) > 0) 222 ++head; 223 if(tail <= head + 1) return false; 224 res.n = 0; 225 for(i = head; i < tail; ++i) 226 res.p[res.n++] = deq[i] * deq[i + 1]; 227 res.p[res.n++] = deq[head] * deq[tail]; 228 res.n = unique(res.p, res.p + res.n) - res.p; 229 res.p[res.n] = res.p[0]; 230 return true; 231 } 232 233 //ix and jx is the points whose distance is return, res.p[n - 1] = res.p[0] 234 double dia_roataing_calipers(Poly &res, int &ix, int &jx) { 235 double dia = 0; 236 int q = 1; 237 for(int i = 0; i < res.n - 1; ++i) { 238 while(sgn(area(res.p[i], res.p[q + 1], res.p[i + 1]) - area(res.p[i], res.p[q], res.p[i + 1])) > 0) 239 q = (q + 1) % (res.n - 1); 240 if(sgn(dist(res.p[i], res.p[q]) - dia) > 0) { 241 dia = dist(res.p[i], res.p[q]); 242 ix = i; jx = q; 243 } 244 if(sgn(dist(res.p[i + 1], res.p[q]) - dia) > 0) { 245 dia = dist(res.p[i + 1], res.p[q]); 246 ix = i + 1; jx = q; 247 } 248 } 249 return dia; 250 } 251 252 /*******************************************************************************************/ 253 254 Point p[MAXN]; 255 int stk[MAXN], top, n; 256 Poly res; 257 258 int dist2(const Point &a, const Point &b) { 259 int x = a.x - b.x, y = a.y - b.y; 260 return x * x + y * y; 261 } 262 263 int main() { 264 scanf("%d", &n); 265 for(int i = 0; i < n; ++i) p[i].read(); 266 Graham_scan(p, n, stk, top); 267 for(int i = 0; i <= top; ++i) res.p[res.n++] = p[stk[i]]; 268 int ans1, ans2; 269 dia_roataing_calipers(res, ans1, ans2); 270 printf("%d\n", dist2(res.p[ans1], res.p[ans2])); 271 }
代码(204MS)(修改了一下,不过是在VJ上交的):
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #include <cmath> 6 using namespace std; 7 8 const int MAXN = 50010; 9 const double EPS = 1e-10; 10 const double PI = acos(-1.0);//3.14159265358979323846 11 const double INF = 1; 12 13 inline int sgn(double x) { 14 return (x > EPS) - (x < -EPS); 15 } 16 17 struct Point { 18 double x, y, ag; 19 Point() {} 20 Point(double x, double y): x(x), y(y) {} 21 void read() { 22 scanf("%lf%lf", &x, &y); 23 } 24 bool operator == (const Point &rhs) const { 25 return sgn(x - rhs.x) == 0 && sgn(y - rhs.y) == 0; 26 } 27 bool operator < (const Point &rhs) const { 28 if(y != rhs.y) return y < rhs.y; 29 return x < rhs.x; 30 } 31 Point operator + (const Point &rhs) const { 32 return Point(x + rhs.x, y + rhs.y); 33 } 34 Point operator - (const Point &rhs) const { 35 return Point(x - rhs.x, y - rhs.y); 36 } 37 Point operator * (const double &b) const { 38 return Point(x * b, y * b); 39 } 40 Point operator / (const double &b) const { 41 return Point(x / b, y / b); 42 } 43 double length() { 44 return sqrt(x * x + y * y); 45 } 46 Point unit() { 47 return *this / length(); 48 } 49 void makeAg() { 50 ag = atan2(y, x); 51 } 52 void print() { 53 printf("%.10f %.10f\n", x, y); 54 } 55 }; 56 typedef Point Vector; 57 58 double dist(const Point &a, const Point &b) { 59 return (a - b).length(); 60 } 61 62 double cross(const Point &a, const Point &b) { 63 return a.x * b.y - a.y * b.x; 64 } 65 //ret >= 0 means turn right 66 double cross(const Point &sp, const Point &ed, const Point &op) { 67 return cross(sp - op, ed - op); 68 } 69 70 double area(const Point& a, const Point &b, const Point &c) { 71 return fabs(cross(a - c, b - c)) / 2; 72 } 73 //counter-clockwise 74 Point rotate(const Point &p, double angle, const Point &o = Point(0, 0)) { 75 Point t = p - o; 76 double x = t.x * cos(angle) - t.y * sin(angle); 77 double y = t.y * cos(angle) + t.x * sin(angle); 78 return Point(x, y) + o; 79 } 80 81 struct Seg { 82 Point st, ed; 83 double ag; 84 Seg() {} 85 Seg(Point st, Point ed): st(st), ed(ed) {} 86 void read() { 87 st.read(); ed.read(); 88 } 89 void makeAg() { 90 ag = atan2(ed.y - st.y, ed.x - st.x); 91 } 92 }; 93 typedef Seg Line; 94 95 //ax + by + c > 0 96 Line buildLine(double a, double b, double c) { 97 if(sgn(a) == 0 && sgn(b) == 0) return Line(Point(sgn(c) > 0 ? -1 : 1, INF), Point(0, INF)); 98 if(sgn(a) == 0) return Line(Point(sgn(b), -c/b), Point(0, -c/b)); 99 if(sgn(b) == 0) return Line(Point(-c/a, 0), Point(-c/a, sgn(a))); 100 if(b < 0) return Line(Point(0, -c/b), Point(1, -(a + c) / b)); 101 else return Line(Point(1, -(a + c) / b), Point(0, -c/b)); 102 } 103 104 void moveRight(Line &v, double r) { 105 double dx = v.ed.x - v.st.x, dy = v.ed.y - v.st.y; 106 dx = dx / dist(v.st, v.ed) * r; 107 dy = dy / dist(v.st, v.ed) * r; 108 v.st.x += dy; v.ed.x += dy; 109 v.st.y -= dx; v.ed.y -= dx; 110 } 111 112 bool isOnSeg(const Seg &s, const Point &p) { 113 return (p == s.st || p == s.ed) || 114 (((p.x - s.st.x) * (p.x - s.ed.x) < 0 || 115 (p.y - s.st.y) * (p.y - s.ed.y) < 0) && 116 sgn(cross(s.ed, p, s.st) == 0)); 117 } 118 119 bool isIntersected(const Point &s1, const Point &e1, const Point &s2, const Point &e2) { 120 return (max(s1.x, e1.x) >= min(s2.x, e2.x)) && 121 (max(s2.x, e2.x) >= min(s1.x, e1.x)) && 122 (max(s1.y, e1.y) >= min(s2.y, e2.y)) && 123 (max(s2.y, e2.y) >= min(s1.y, e1.y)) && 124 (cross(s2, e1, s1) * cross(e1, e2, s1) >= 0) && 125 (cross(s1, e2, s2) * cross(e2, e1, s2) >= 0); 126 } 127 128 bool isIntersected(const Seg &a, const Seg &b) { 129 return isIntersected(a.st, a.ed, b.st, b.ed); 130 } 131 132 bool isParallel(const Seg &a, const Seg &b) { 133 return sgn(cross(a.ed - a.st, b.ed - b.st)) == 0; 134 } 135 136 //return Ax + By + C =0 's A, B, C 137 void Coefficient(const Line &L, double &A, double &B, double &C) { 138 A = L.ed.y - L.st.y; 139 B = L.st.x - L.ed.x; 140 C = L.ed.x * L.st.y - L.st.x * L.ed.y; 141 } 142 //point of intersection 143 Point operator * (const Line &a, const Line &b) { 144 double A1, B1, C1; 145 double A2, B2, C2; 146 Coefficient(a, A1, B1, C1); 147 Coefficient(b, A2, B2, C2); 148 Point I; 149 I.x = - (B2 * C1 - B1 * C2) / (A1 * B2 - A2 * B1); 150 I.y = (A2 * C1 - A1 * C2) / (A1 * B2 - A2 * B1); 151 return I; 152 } 153 154 bool isEqual(const Line &a, const Line &b) { 155 double A1, B1, C1; 156 double A2, B2, C2; 157 Coefficient(a, A1, B1, C1); 158 Coefficient(b, A2, B2, C2); 159 return sgn(A1 * B2 - A2 * B1) == 0 && sgn(A1 * C2 - A2 * C1) == 0 && sgn(B1 * C2 - B2 * C1) == 0; 160 } 161 162 struct Poly { 163 int n; 164 Point p[MAXN];//p[n] = p[0] 165 void init(Point *pp, int nn) { 166 n = nn; 167 for(int i = 0; i < n; ++i) p[i] = pp[i]; 168 p[n] = p[0]; 169 } 170 double area() { 171 if(n < 3) return 0; 172 double s = p[0].y * (p[n - 1].x - p[1].x); 173 for(int i = 1; i < n; ++i) 174 s += p[i].y * (p[i - 1].x - p[i + 1].x); 175 return s / 2; 176 } 177 }; 178 //the convex hull is clockwise 179 void Graham_scan(Point *p, int n, int *stk, int &top) {//stk[0] = stk[top] 180 sort(p, p + n); 181 top = 1; 182 stk[0] = 0; stk[1] = 1; 183 for(int i = 2; i < n; ++i) { 184 while(top && cross(p[i], p[stk[top]], p[stk[top - 1]]) <= 0) --top; 185 stk[++top] = i; 186 } 187 int len = top; 188 stk[++top] = n - 2; 189 for(int i = n - 3; i >= 0; --i) { 190 while(top != len && cross(p[i], p[stk[top]], p[stk[top - 1]]) <= 0) --top; 191 stk[++top] = i; 192 } 193 } 194 //use for half_planes_cross 195 bool cmpAg(const Line &a, const Line &b) { 196 if(sgn(a.ag - b.ag) == 0) 197 return sgn(cross(b.ed, a.st, b.st)) < 0; 198 return a.ag < b.ag; 199 } 200 //clockwise, plane is on the right 201 bool half_planes_cross(Line *v, int vn, Poly &res, Line *deq) { 202 int i, n; 203 sort(v, v + vn, cmpAg); 204 for(i = n = 1; i < vn; ++i) { 205 if(sgn(v[i].ag - v[i-1].ag) == 0) continue; 206 v[n++] = v[i]; 207 } 208 int head = 0, tail = 1; 209 deq[0] = v[0], deq[1] = v[1]; 210 for(i = 2; i < n; ++i) { 211 if(isParallel(deq[tail - 1], deq[tail]) || isParallel(deq[head], deq[head + 1])) 212 return false; 213 while(head < tail && sgn(cross(v[i].ed, deq[tail - 1] * deq[tail], v[i].st)) > 0) 214 --tail; 215 while(head < tail && sgn(cross(v[i].ed, deq[head] * deq[head + 1], v[i].st)) > 0) 216 ++head; 217 deq[++tail] = v[i]; 218 } 219 while(head < tail && sgn(cross(deq[head].ed, deq[tail - 1] * deq[tail], deq[head].st)) > 0) 220 --tail; 221 while(head < tail && sgn(cross(deq[tail].ed, deq[head] * deq[head + 1], deq[tail].st)) > 0) 222 ++head; 223 if(tail <= head + 1) return false; 224 res.n = 0; 225 for(i = head; i < tail; ++i) 226 res.p[res.n++] = deq[i] * deq[i + 1]; 227 res.p[res.n++] = deq[head] * deq[tail]; 228 res.n = unique(res.p, res.p + res.n) - res.p; 229 res.p[res.n] = res.p[0]; 230 return true; 231 } 232 233 //ix and jx is the points whose distance is return, res.p[n - 1] = res.p[0], res must be clockwise 234 double dia_roataing_calipers(Poly &res, int &ix, int &jx) { 235 double dia = 0; 236 int q = 1; 237 for(int i = 0; i < res.n - 1; ++i) { 238 while(sgn(cross(res.p[i], res.p[q + 1], res.p[i + 1]) - cross(res.p[i], res.p[q], res.p[i + 1])) > 0) 239 q = (q + 1) % (res.n - 1); 240 if(sgn(dist(res.p[i], res.p[q]) - dia) > 0) { 241 dia = dist(res.p[i], res.p[q]); 242 ix = i; jx = q; 243 } 244 if(sgn(dist(res.p[i + 1], res.p[q]) - dia) > 0) { 245 dia = dist(res.p[i + 1], res.p[q]); 246 ix = i + 1; jx = q; 247 } 248 } 249 return dia; 250 } 251 252 /*******************************************************************************************/ 253 254 Point p[MAXN]; 255 int stk[MAXN], top, n; 256 Poly res; 257 258 int dist2(const Point &a, const Point &b) { 259 int x = a.x - b.x, y = a.y - b.y; 260 return x * x + y * y; 261 } 262 263 int main() { 264 scanf("%d", &n); 265 for(int i = 0; i < n; ++i) p[i].read(); 266 Graham_scan(p, n, stk, top); 267 for(int i = 0; i <= top; ++i) res.p[res.n++] = p[stk[i]]; 268 int ans1, ans2; 269 dia_roataing_calipers(res, ans1, ans2); 270 printf("%d\n", dist2(res.p[ans1], res.p[ans2])); 271 }