【几何】【凸包】【模板】POJ1584 - A Round Peg in a Ground Hole
A Round Peg in a Ground Hole
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 7061 | Accepted: 2297 |
Description
The DIY Furniture company specializes in assemble-it-yourself furniture kits. Typically, the pieces of wood are attached to one another using a wooden peg that fits into pre-cut holes in each piece to be attached. The pegs have a circular cross-section and so are intended to fit inside a round hole.
A recent factory run of computer desks were flawed when an automatic grinding machine was mis-programmed. The result is an irregularly shaped hole in one piece that, instead of the expected circular shape, is actually an irregular polygon. You need to figure out whether the desks need to be scrapped or if they can be salvaged by filling a part of the hole with a mixture of wood shavings and glue.
There are two concerns. First, if the hole contains any protrusions (i.e., if there exist any two interior points in the hole that, if connected by a line segment, that segment would cross one or more edges of the hole), then the filled-in-hole would not be structurally sound enough to support the peg under normal stress as the furniture is used. Second, assuming the hole is appropriately shaped, it must be big enough to allow insertion of the peg. Since the hole in this piece of wood must match up with a corresponding hole in other pieces, the precise location where the peg must fit is known.
Write a program to accept descriptions of pegs and polygonal holes and determine if the hole is ill-formed and, if not, whether the peg will fit at the desired location. Each hole is described as a polygon with vertices (x1, y1), (x2, y2), . . . , (xn, yn). The edges of the polygon are (xi, yi) to (xi+1, yi+1) for i = 1 . . . n − 1 and (xn, yn) to (x1, y1).
A recent factory run of computer desks were flawed when an automatic grinding machine was mis-programmed. The result is an irregularly shaped hole in one piece that, instead of the expected circular shape, is actually an irregular polygon. You need to figure out whether the desks need to be scrapped or if they can be salvaged by filling a part of the hole with a mixture of wood shavings and glue.
There are two concerns. First, if the hole contains any protrusions (i.e., if there exist any two interior points in the hole that, if connected by a line segment, that segment would cross one or more edges of the hole), then the filled-in-hole would not be structurally sound enough to support the peg under normal stress as the furniture is used. Second, assuming the hole is appropriately shaped, it must be big enough to allow insertion of the peg. Since the hole in this piece of wood must match up with a corresponding hole in other pieces, the precise location where the peg must fit is known.
Write a program to accept descriptions of pegs and polygonal holes and determine if the hole is ill-formed and, if not, whether the peg will fit at the desired location. Each hole is described as a polygon with vertices (x1, y1), (x2, y2), . . . , (xn, yn). The edges of the polygon are (xi, yi) to (xi+1, yi+1) for i = 1 . . . n − 1 and (xn, yn) to (x1, y1).
Input
Input consists of a series of piece descriptions. Each piece description consists of the following data:
Line 1 < nVertices > < pegRadius > < pegX > < pegY >
number of vertices in polygon, n (integer)
radius of peg (real)
X and Y position of peg (real)
n Lines < vertexX > < vertexY >
On a line for each vertex, listed in order, the X and Y position of vertex The end of input is indicated by a number of polygon vertices less than 3.
Line 1 < nVertices > < pegRadius > < pegX > < pegY >
number of vertices in polygon, n (integer)
radius of peg (real)
X and Y position of peg (real)
n Lines < vertexX > < vertexY >
On a line for each vertex, listed in order, the X and Y position of vertex The end of input is indicated by a number of polygon vertices less than 3.
Output
For each piece description, print a single line containing the string:
HOLE IS ILL-FORMED if the hole contains protrusions
PEG WILL FIT if the hole contains no protrusions and the peg fits in the hole at the indicated position
PEG WILL NOT FIT if the hole contains no protrusions but the peg will not fit in the hole at the indicated position
HOLE IS ILL-FORMED if the hole contains protrusions
PEG WILL FIT if the hole contains no protrusions and the peg fits in the hole at the indicated position
PEG WILL NOT FIT if the hole contains no protrusions but the peg will not fit in the hole at the indicated position
Sample Input
5 1.5 1.5 2.0 1.0 1.0 2.0 2.0 1.75 2.0 1.0 3.0 0.0 2.0 5 1.5 1.5 2.0 1.0 1.0 2.0 2.0 1.75 2.5 1.0 3.0 0.0 2.0 1
Sample Output
HOLE IS ILL-FORMED PEG WILL NOT FIT
Solution
题意:已知一个多边形的n个顶点坐标,然后再给一个钉子,给定钉子的半径和圆心坐标,首先判断多边形是否为凸多边形,若为凸多边形,再判断钉子是否可以放到凸多边形内部。
思路:
先判断给定多边形是否为凸多边形。可以直接求凸包(凸包上可以有连续三点共线)后再判断凸包上点的个数是否小于n,复杂度O(nlogn)。也可以判断所有相邻边的叉积是否同号(偏转方向相同),复杂度O(nlogn)。
再判断给定的钉子是否在多边形内。可以二分判断一个点是否在凸包内,不详述原理,复杂度O(nlogn)。也可以用转角法判断一个点是否在多边形内(不管是不是凸包),复杂度O(n)。也可以用叉积判断所有角度正负,复杂度O(n)。
下面是我的某个版本的代码(多边形部分自己写的,不保证正确):
1 #include <iostream> 2 #include <cstdio> 3 #include <cmath> 4 #include <vector> 5 #include <algorithm> 6 #include <iomanip> 7 #define MAX_N 100 8 using namespace std; 9 10 11 /////////////////////////////////////////////////////////////////// 12 //常量区 13 const double INF = 1e12; // 无穷大 14 const double EPS = 1e-9; // 计算精度 15 const int LEFT = 0; // 点在直线左边 16 const int RIGHT = 1; // 点在直线右边 17 const int ONLINE = 2; // 点在直线上 18 const int CROSS = 0; // 两直线相交 19 const int COLINE = 1; // 两直线共线 20 const int PARALLEL = 2; // 两直线平行 21 const int NOTCOPLANAR = 3; // 两直线不共面 22 const int INSIDE = 1; // 点在图形内部 23 const int OUTSIDE = 2; // 点在图形外部 24 const int BORDER = 3; // 点在图形边界 25 const int BAOHAN = 1; // 大圆包含小圆 26 const int NEIQIE = 2; // 内切 27 const int XIANJIAO = 3; // 相交 28 const int WAIQIE = 4; // 外切 29 const int XIANGLI = 5; // 相离 30 const double pi = acos(-1.0); //圆周率 31 /////////////////////////////////////////////////////////////////// 32 33 34 /////////////////////////////////////////////////////////////////// 35 //类型定义区 36 struct Point { // 二维点或矢量 37 double x, y; 38 Point() {} 39 Point(double x0, double y0): x(x0), y(y0) {} 40 }; 41 struct Point3D { //三维点或矢量 42 double x, y, z; 43 Point3D() {} 44 Point3D(double x0, double y0, double z0): x(x0), y(y0), z(z0) {} 45 }; 46 struct Line { // 二维的直线或线段 47 Point p1, p2; 48 Line() {} 49 Line(Point p10, Point p20): p1(p10), p2(p20) {} 50 }; 51 struct Line3D { // 三维的直线或线段 52 Point3D p1, p2; 53 Line3D() {} 54 Line3D(Point3D p10, Point3D p20): p1(p10), p2(p20) {} 55 }; 56 struct Rect { // 用长宽表示矩形的方法 w, h分别表示宽度和高度 57 double w, h; 58 Rect() {} 59 Rect(double _w,double _h) : w(_w),h(_h) {} 60 }; 61 struct Rect_2 { // 表示矩形,左下角坐标是(xl, yl),右上角坐标是(xh, yh) 62 double xl, yl, xh, yh; 63 Rect_2() {} 64 Rect_2(double _xl,double _yl,double _xh,double _yh) : xl(_xl),yl(_yl),xh(_xh),yh(_yh) {} 65 }; 66 struct Circle { //圆 67 Point c; 68 double r; 69 Circle() {} 70 Circle(Point _c,double _r) :c(_c),r(_r) {} 71 }; 72 typedef vector<Point> Polygon; // 二维多边形 73 typedef vector<Point> Points; // 二维点集 74 typedef vector<Point3D> Points3D; // 三维点集 75 /////////////////////////////////////////////////////////////////// 76 77 78 /////////////////////////////////////////////////////////////////// 79 //基本函数区 80 inline double max(double x,double y) 81 { 82 return x > y ? x : y; 83 } 84 inline double min(double x, double y) 85 { 86 return x > y ? y : x; 87 } 88 inline bool ZERO(double x) // x == 0 89 { 90 return (fabs(x) < EPS); 91 } 92 inline bool ZERO(Point p) // p == 0 93 { 94 return (ZERO(p.x) && ZERO(p.y)); 95 } 96 inline bool ZERO(Point3D p) // p == 0 97 { 98 return (ZERO(p.x) && ZERO(p.y) && ZERO(p.z)); 99 } 100 inline bool EQ(double x, double y) // eqaul, x == y 101 { 102 return (fabs(x - y) < EPS); 103 } 104 inline bool NEQ(double x, double y) // not equal, x != y 105 { 106 return (fabs(x - y) >= EPS); 107 } 108 inline bool LT(double x, double y) // less than, x < y 109 { 110 return ( NEQ(x, y) && (x < y) ); 111 } 112 inline bool GT(double x, double y) // greater than, x > y 113 { 114 return ( NEQ(x, y) && (x > y) ); 115 } 116 inline bool LEQ(double x, double y) // less equal, x <= y 117 { 118 return ( EQ(x, y) || (x < y) ); 119 } 120 inline bool GEQ(double x, double y) // greater equal, x >= y 121 { 122 return ( EQ(x, y) || (x > y) ); 123 } 124 inline int dSign(double x){ 125 if(ZERO(x)) return 0; 126 return x > 0 ? 1 : -1; 127 } 128 // 注意!!! 129 // 如果是一个很小的负的浮点数 130 // 保留有效位数输出的时候会出现-0.000这样的形式, 131 // 前面多了一个负号 132 // 这就会导致错误!!!!!! 133 // 因此在输出浮点数之前,一定要调用次函数进行修正! 134 inline double FIX(double x) 135 { 136 return (fabs(x) < EPS) ? 0 : x; 137 } 138 ////////////////////////////////////////////////////////////////////////////////////// 139 140 141 ///////////////////////////////////////////////////////////////////////////////////// 142 //二维矢量运算 143 bool operator==(Point p1, Point p2) 144 { 145 return ( EQ(p1.x, p2.x) && EQ(p1.y, p2.y) ); 146 } 147 bool operator!=(Point p1, Point p2) 148 { 149 return ( NEQ(p1.x, p2.x) || NEQ(p1.y, p2.y) ); 150 } 151 bool operator<(Point p1, Point p2) 152 { 153 if (NEQ(p1.x, p2.x)) { 154 return (p1.x < p2.x); 155 } else { 156 return (p1.y < p2.y); 157 } 158 } 159 Point operator+(Point p1, Point p2) 160 { 161 return Point(p1.x + p2.x, p1.y + p2.y); 162 } 163 Point operator-(Point p1, Point p2) 164 { 165 return Point(p1.x - p2.x, p1.y - p2.y); 166 } 167 double operator*(Point p1, Point p2) // 计算叉乘 p1 × p2 168 { 169 return (p1.x * p2.y - p2.x * p1.y); 170 } 171 double operator&(Point p1, Point p2) { // 计算点积 p1·p2 172 return (p1.x * p2.x + p1.y * p2.y); 173 } 174 double Norm(Point p) // 计算矢量p的模 175 { 176 return sqrt(p.x * p.x + p.y * p.y); 177 } 178 // 把矢量p旋转角度angle (弧度表示) 179 // angle > 0表示逆时针旋转 180 // angle < 0表示顺时针旋转 181 Point Rotate(Point p, double angle) 182 { 183 Point result; 184 result.x = p.x * cos(angle) - p.y * sin(angle); 185 result.y = p.x * sin(angle) + p.y * cos(angle); 186 return result; 187 } 188 ////////////////////////////////////////////////////////////////////////////////////// 189 190 191 ////////////////////////////////////////////////////////////////////////////////////// 192 //三维矢量运算 193 bool operator==(Point3D p1, Point3D p2) 194 { 195 return ( EQ(p1.x, p2.x) && EQ(p1.y, p2.y) && EQ(p1.z, p2.z) ); 196 } 197 bool operator<(Point3D p1, Point3D p2) 198 { 199 if (NEQ(p1.x, p2.x)) { 200 return (p1.x < p2.x); 201 } else if (NEQ(p1.y, p2.y)) { 202 return (p1.y < p2.y); 203 } else { 204 return (p1.z < p2.z); 205 } 206 } 207 Point3D operator+(Point3D p1, Point3D p2) 208 { 209 return Point3D(p1.x + p2.x, p1.y + p2.y, p1.z + p2.z); 210 } 211 Point3D operator-(Point3D p1, Point3D p2) 212 { 213 return Point3D(p1.x - p2.x, p1.y - p2.y, p1.z - p2.z); 214 } 215 Point3D operator*(Point3D p1, Point3D p2) // 计算叉乘 p1 x p2 216 { 217 return Point3D(p1.y * p2.z - p1.z * p2.y, 218 p1.z * p2.x - p1.x * p2.z, 219 p1.x * p2.y - p1.y * p2.x ); 220 } 221 double operator&(Point3D p1, Point3D p2) { // 计算点积 p1·p2 222 return (p1.x * p2.x + p1.y * p2.y + p1.z * p2.z); 223 } 224 double Norm(Point3D p) // 计算矢量p的模 225 { 226 return sqrt(p.x * p.x + p.y * p.y + p.z * p.z); 227 } 228 229 230 ////////////////////////////////////////////////////////////////////////////////////// 231 232 233 ///////////////////////////////////////////////////////////////////////////////////// 234 //点.线段.直线问题 235 // 236 double Distance(Point p1, Point p2) //2点间的距离 237 { 238 return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y)); 239 } 240 double Distance(Point3D p1, Point3D p2) //2点间的距离,三维 241 { 242 return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y)+(p1.z-p2.z)*(p1.z-p2.z)); 243 } 244 double Distance(Point p, Line L) // 求二维平面上点到直线的距离 245 { 246 return ( fabs((p - L.p1) * (L.p2 - L.p1)) / Norm(L.p2 - L.p1) ); 247 } 248 double Distance(Point3D p, Line3D L)// 求三维空间中点到直线的距离 249 { 250 return ( Norm((p - L.p1) * (L.p2 - L.p1)) / Norm(L.p2 - L.p1) ); 251 } 252 bool OnLine(Point p, Line L) // 判断二维平面上点p是否在直线L上 253 { 254 return ZERO( (p - L.p1) * (L.p2 - L.p1) ); 255 } 256 bool OnLine(Point3D p, Line3D L) // 判断三维空间中点p是否在直线L上 257 { 258 return ZERO( (p - L.p1) * (L.p2 - L.p1) ); 259 } 260 int Relation(Point p, Line L) // 计算点p与直线L的相对关系 ,返回ONLINE,LEFT,RIGHT 261 { 262 double res = (L.p2 - L.p1) * (p - L.p1); 263 if (EQ(res, 0)) { 264 return ONLINE; 265 } else if (res > 0) { 266 return LEFT; 267 } else { 268 return RIGHT; 269 } 270 } 271 bool SameSide(Point p1, Point p2, Line L) // 判断点p1, p2是否在直线L的同侧 272 { 273 double m1 = (p1 - L.p1) * (L.p2 - L.p1); 274 double m2 = (p2 - L.p1) * (L.p2 - L.p1); 275 return GT(m1 * m2, 0); 276 } 277 bool IsPointOnLineSeg(Point p, Line L) // 判断二维平面上点p是否在线段l上 278 { 279 return ( ZERO( (L.p1 - p) * (L.p2 - p) ) && 280 LEQ((p.x - L.p1.x)*(p.x - L.p2.x), 0) && 281 LEQ((p.y - L.p1.y)*(p.y - L.p2.y), 0) ); 282 } 283 bool IsPointOnLineSeg(Point3D p, Line3D L) // 判断三维空间中点p是否在线段l上 284 { 285 return ( ZERO((L.p1 - p) * (L.p2 - p)) && 286 EQ( Norm(p - L.p1) + Norm(p - L.p2), Norm(L.p2 - L.p1)) ); 287 } 288 Point SymPoint(Point p, Line L) // 求二维平面上点p关于直线L的对称点 289 { 290 Point result; 291 double a = L.p2.x - L.p1.x; 292 double b = L.p2.y - L.p1.y; 293 double t = ( (p.x - L.p1.x) * a + (p.y - L.p1.y) * b ) / (a*a + b*b); 294 result.x = 2 * L.p1.x + 2 * a * t - p.x; 295 result.y = 2 * L.p1.y + 2 * b * t - p.y; 296 return result; 297 } 298 bool Coplanar(Points3D points) // 判断一个点集中的点是否全部共面 299 { 300 int i; 301 Point3D p; 302 303 304 if (points.size() < 4) return true; 305 p = (points[2] - points[0]) * (points[1] - points[0]); 306 for (i = 3; i < points.size(); i++) { 307 if (! ZERO(p & points[i]) ) return false; 308 } 309 return true; 310 } 311 bool LineIntersect(Line L1, Line L2) // 判断二维的两直线是否相交 312 { 313 return (! ZERO((L1.p1 - L1.p2)*(L2.p1 - L2.p2)) ); // 是否平行 314 } 315 bool LineIntersect(Line3D L1, Line3D L2) // 判断三维的两直线是否相交 316 { 317 Point3D p1 = L1.p1 - L1.p2; 318 Point3D p2 = L2.p1 - L2.p2; 319 Point3D p = p1 * p2; 320 if (ZERO(p)) return false; // 是否平行 321 p = (L2.p1 - L1.p2) * (L1.p1 - L1.p2); 322 return ZERO(p & L2.p2); // 是否共面 323 } 324 bool LineSegIntersect(Line L1, Line L2) // 判断二维的两条线段是否相交 325 { 326 return ( GEQ( max(L1.p1.x, L1.p2.x), min(L2.p1.x, L2.p2.x) ) && 327 GEQ( max(L2.p1.x, L2.p2.x), min(L1.p1.x, L1.p2.x) ) && 328 GEQ( max(L1.p1.y, L1.p2.y), min(L2.p1.y, L2.p2.y) ) && 329 GEQ( max(L2.p1.y, L2.p2.y), min(L1.p1.y, L1.p2.y) ) && 330 LEQ( ((L2.p1 - L1.p1) * (L1.p2 - L1.p1)) * ((L2.p2 - L1.p1) * (L1.p2 - L1.p1)), 0 ) && 331 LEQ( ((L1.p1 - L2.p1) * (L2.p2 - L2.p1)) * ((L1.p2 - L2.p1) * (L2.p2 - L2.p1)), 0 ) ); 332 } 333 bool LineSegIntersect(Line3D L1, Line3D L2) // 判断三维的两条线段是否相交 334 { 335 // todo 336 return true; 337 } 338 // 计算两条二维直线的交点,结果在参数P中返回 339 // 返回值说明了两条直线的位置关系: COLINE -- 共线 PARALLEL -- 平行 CROSS -- 相交 340 int CalCrossPoint(Line L1, Line L2, Point& P) 341 { 342 double A1, B1, C1, A2, B2, C2; 343 344 345 A1 = L1.p2.y - L1.p1.y; 346 B1 = L1.p1.x - L1.p2.x; 347 C1 = L1.p2.x * L1.p1.y - L1.p1.x * L1.p2.y; 348 349 350 A2 = L2.p2.y - L2.p1.y; 351 B2 = L2.p1.x - L2.p2.x; 352 C2 = L2.p2.x * L2.p1.y - L2.p1.x * L2.p2.y; 353 354 355 if (EQ(A1 * B2, B1 * A2)) { 356 if (EQ( (A1 + B1) * C2, (A2 + B2) * C1 )) { 357 return COLINE; 358 } else { 359 return PARALLEL; 360 } 361 } else { 362 P.x = (B2 * C1 - B1 * C2) / (A2 * B1 - A1 * B2); 363 P.y = (A1 * C2 - A2 * C1) / (A2 * B1 - A1 * B2); 364 return CROSS; 365 } 366 } 367 // 计算两条三维直线的交点,结果在参数P中返回 368 // 返回值说明了两条直线的位置关系 COLINE -- 共线 PARALLEL -- 平行 CROSS -- 相交 NONCOPLANAR -- 不公面 369 int CalCrossPoint(Line3D L1, Line3D L2, Point3D& P) 370 { 371 // todo 372 return 0; 373 } 374 // 计算点P到直线L的最近点 375 Point NearestPointToLine(Point P, Line L) 376 { 377 Point result; 378 double a, b, t; 379 380 a = L.p2.x - L.p1.x; 381 b = L.p2.y - L.p1.y; 382 t = ( (P.x - L.p1.x) * a + (P.y - L.p1.y) * b ) / (a * a + b * b); 383 384 result.x = L.p1.x + a * t; 385 result.y = L.p1.y + b * t; 386 return result; 387 } 388 // 计算点P到线段L的最近点 389 Point NearestPointToLineSeg(Point P, Line L) 390 { 391 Point result; 392 double a, b, t; 393 394 a = L.p2.x - L.p1.x; 395 b = L.p2.y - L.p1.y; 396 t = ( (P.x - L.p1.x) * a + (P.y - L.p1.y) * b ) / (a * a + b * b); 397 398 if ( GEQ(t, 0) && LEQ(t, 1) ) { 399 result.x = L.p1.x + a * t; 400 result.y = L.p1.y + b * t; 401 } else { 402 if ( Norm(P - L.p1) < Norm(P - L.p2) ) { 403 result = L.p1; 404 } else { 405 result = L.p2; 406 } 407 } 408 return result; 409 } 410 // 计算险段L1到线段L2的最短距离 411 double MinDistance(Line L1, Line L2) 412 { 413 double d1, d2, d3, d4; 414 415 416 if (LineSegIntersect(L1, L2)) { 417 return 0; 418 } else { 419 d1 = Norm( NearestPointToLineSeg(L1.p1, L2) - L1.p1 ); 420 d2 = Norm( NearestPointToLineSeg(L1.p2, L2) - L1.p2 ); 421 d3 = Norm( NearestPointToLineSeg(L2.p1, L1) - L2.p1 ); 422 d4 = Norm( NearestPointToLineSeg(L2.p2, L1) - L2.p2 ); 423 424 return min( min(d1, d2), min(d3, d4) ); 425 } 426 } 427 // 求二维两直线的夹角, 428 // 返回值是0~Pi之间的弧度 429 double Inclination(Line L1, Line L2) 430 { 431 Point u = L1.p2 - L1.p1; 432 Point v = L2.p2 - L2.p1; 433 return acos( (u & v) / (Norm(u)*Norm(v)) ); 434 } 435 // 求三维两直线的夹角, 436 // 返回值是0~Pi之间的弧度 437 double Inclination(Line3D L1, Line3D L2) 438 { 439 Point3D u = L1.p2 - L1.p1; 440 Point3D v = L2.p2 - L2.p1; 441 return acos( (u & v) / (Norm(u)*Norm(v)) ); 442 } 443 ///////////////////////////////////////////////////////////////////////////// 444 445 446 ///////////////////////////////////////////////////////////////////////////// 447 // 判断两个矩形是否相交 448 // 如果相邻不算相交 449 bool Intersect(Rect_2 r1, Rect_2 r2) 450 { 451 return ( max(r1.xl, r2.xl) < min(r1.xh, r2.xh) && 452 max(r1.yl, r2.yl) < min(r1.yh, r2.yh) ); 453 } 454 // 判断矩形r2是否可以放置在矩形r1内 455 // r2可以任意地旋转 456 //发现原来的给出的方法过不了OJ上的无归之室这题, 457 //所以用了自己的代码 458 bool IsContain(Rect r1, Rect r2) //矩形的w>h 459 { 460 if(r1.w >r2.w && r1.h > r2.h) return true; 461 else 462 { 463 double r = sqrt(r2.w*r2.w + r2.h*r2.h) / 2.0; 464 double alpha = atan2(r2.h,r2.w); 465 double sita = asin((r1.h/2.0)/r); 466 double x = r * cos(sita - 2*alpha); 467 double y = r * sin(sita - 2*alpha); 468 if(x < r1.w/2.0 && y < r1.h/2.0 && x > 0 && y > -r1.h/2.0) return true; 469 else return false; 470 } 471 } 472 473 474 //////////////////////////////////////////////////////////////////////// 475 /**圆**/ 476 477 478 Point Center(const Circle & C) //圆心 479 { 480 return C.c; 481 } 482 483 double Area(const Circle &C) 484 { 485 return pi*C.r*C.r; 486 } 487 488 double CommonArea(const Circle & A, const Circle & B) //两个圆的公共面积 489 { 490 double area = 0.0; 491 const Circle & M = (A.r > B.r) ? A : B; 492 const Circle & N = (A.r > B.r) ? B : A; 493 double D = Distance(Center(M), Center(N)); 494 if ((D < M.r + N.r) && (D > M.r - N.r)) 495 { 496 double cosM = (M.r * M.r + D * D - N.r * N.r) / (2.0 * M.r * D); 497 double cosN = (N.r * N.r + D * D - M.r * M.r) / (2.0 * N.r * D); 498 double alpha = 2.0 * acos(cosM); 499 double beta = 2.0 * acos(cosN); 500 double TM = 0.5 * M.r * M.r * sin(alpha); 501 double TN = 0.5 * N.r * N.r * sin(beta); 502 double FM = (alpha / (2*pi)) * Area(M); 503 double FN = (beta / (2*pi)) * Area(N); 504 area = FM + FN - TM - TN; 505 } 506 else if (D <= M.r - N.r) 507 { 508 area = Area(N); 509 } 510 return area; 511 } 512 513 bool IsInCircle(const Circle & C, const Rect_2 & rect)//判断圆是否在矩形内(不允许相切) 514 { 515 return (GT(C.c.x - C.r, rect.xl) 516 && LT(C.c.x + C.r, rect.xh) 517 && GT(C.c.y - C.r, rect.yl) 518 && LT(C.c.y + C.r, rect.yh)); 519 } 520 521 522 //判断2圆的位置关系 523 //返回: 524 //BAOHAN = 1; // 大圆包含小圆 525 //NEIQIE = 2; // 内切 526 //XIANJIAO = 3; // 相交 527 //WAIQIE = 4; // 外切 528 //XIANGLI = 5; // 相离 529 int CirCir(const Circle &c1, const Circle &c2)//判断2圆的位置关系 530 { 531 double dis = Distance(c1.c,c2.c); 532 if(LT(dis,fabs(c1.r-c2.r))) return BAOHAN; 533 if(EQ(dis,fabs(c1.r-c2.r))) return NEIQIE; 534 if(LT(dis,c1.r+c2.r) && GT(dis,fabs(c1.r-c2.r))) return XIANJIAO; 535 if(EQ(dis,c1.r+c2.r)) return WAIQIE; 536 return XIANGLI; 537 } 538 539 540 541 //////////////////////////////////////////////////////////////////////// 542 /**多边形**/ 543 544 545 bool cmp(Point A, Point B){ 546 if(NEQ(A.x,B.x)) return LT(A.x,B.x); 547 return LT(A.y,B.y); 548 } 549 550 //求凸包、逆时针顺序 551 //凸包上无连续三点共线 552 int ConvexHull(Point* p,int n,Point* ch){ 553 sort(p,p+n,cmp); 554 int m = 0; 555 for(int i = 0;i < n;++i){ 556 while(m > 1 && LEQ((ch[m-1]-ch[m-2])*(p[i]-ch[m-2]),0)) m--; 557 ch[m++] = p[i]; 558 } 559 int k = m; 560 for(int i = n-2;i >= 0;i--){ 561 while(m > k && LEQ((ch[m-1]-ch[m-2])*(p[i]-ch[m-2]),0)) m--; 562 ch[m++] = p[i]; 563 } 564 if(n > 1) m--; 565 return m; 566 } 567 568 //凸包上可以有连续三点共线 569 int ConvexHull_Colinear(Point* p,int n,Point* ch){ 570 sort(p,p+n,cmp); 571 int m = 0; 572 for(int i = 0;i < n;++i){ 573 while(m > 1 && LT((ch[m-1]-ch[m-2])*(p[i]-ch[m-2]),0)) m--; 574 ch[m++] = p[i]; 575 } 576 int k = m; 577 for(int i = n-2;i >= 0;i--){ 578 while(m > k && LT((ch[m-1]-ch[m-2])*(p[i]-ch[m-2]),0)) m--; 579 ch[m++] = p[i]; 580 } 581 if(n > 1) m--; 582 return m; 583 } 584 585 //点是否在凸包内 586 //二分实现,复杂度 O(logn)。注意要是凸包,逆时针顺序 587 bool IsPointInConvexHull(Point p,Point* ch,int n){ 588 int l = 1, r = n - 2; 589 while(l <= r){ 590 int mid = (l + r) >> 1; 591 double t1 = (ch[mid]-ch[0])*(p-ch[0]); 592 double t2 = (ch[mid+1]-ch[0])*(p-ch[0]); 593 if(GEQ(t1,0) && LEQ(t2,0)){ 594 if(GEQ((ch[mid+1]-ch[mid])*(p-ch[mid]),0)) 595 return true; 596 return false; 597 } 598 else if(LT(t1,0)) r = mid - 1; 599 else l = mid + 1; 600 } 601 return false; 602 } 603 604 //点是否在凸包内 605 //用叉积顺次得到各个角度的符号,若全部同号则点在凸多边形内。否则不在凸多边形内。复杂度 O(n)。顺时针或逆时针都可以 606 //1: 在内部 0: 在外部 -1: 在多边形上 607 int IsPointInConvexHull2(Point p,Point* ch,int n){ 608 int r = 0; 609 for(int i = 0;i < n;++i){ 610 int t = dSign((p-ch[i])*(ch[(i+1)%n]-ch[i])); 611 if(t == 0){ 612 if(IsPointOnLineSeg(p,Line(ch[i],ch[(i+1)%n]))) return -1; 613 else return 0; 614 } 615 if(r * t < 0) return 0; 616 r = t; 617 } 618 return 1; 619 } 620 621 //点是否在多边形内(不必是凸包,多边形需是逆时针排列) 622 //转角法实现,代码参考《训练指南》 623 // 1: 在内部 0: 在外部 -1: 在多边形上 624 int IsPointInPolygon(Point p,Point* poly,int n){ 625 int w = 0; 626 for(int i = 0;i < n;++i){ 627 if(IsPointOnLineSeg(p,Line(poly[i],poly[(i+1)%n]))) return -1; 628 int k = dSign((poly[(i+1)%n]-poly[i])*(p-poly[i])); 629 int d1 = dSign(poly[i].y-p.y); 630 int d2 = dSign(poly[(i+1)%n].y-p.y); 631 if(k > 0 && d1 <= 0 && d2 > 0) w++; 632 if(k < 0 && d2 <= 0 && d1 > 0) w--; 633 } 634 if(w != 0) return 1; 635 return 0; 636 } 637 638 //多边形是否是凸包 639 //复杂度O(n),多边形需是顺时针或逆时针排列 640 //n必须大于等于3。允许连续三点共线 641 bool IsPolygonConvex(Point* poly,int n){ 642 int r = 0; 643 for(int i = 0;i < n;++i){ 644 int t = dSign((poly[(i+1)%n]-poly[i])*(poly[(i+2)%n]-poly[(i+1)%n])); 645 if(r * t < 0) return 0; 646 if(t) r = t; 647 } 648 return 1; 649 } 650 651 //////////////////////////////////////////////////////////////////////// 652 653 int n; 654 double pr; 655 Point peg,vert[100010],cHull[100010]; 656 657 int main(){ 658 ios::sync_with_stdio(false); 659 while(cin >> n && n >= 3){ 660 cin >> pr >> peg.x >> peg.y; 661 for(int i = 0;i < n;++i) cin >> vert[i].x >> vert[i].y; 662 if(!IsPolygonConvex(vert,n)){ 663 cout << "HOLE IS ILL-FORMED" << endl; 664 continue; 665 } 666 if(IsPointInConvexHull2(peg,vert,n) == 1){ 667 bool fit = 1; 668 for(int i = 0;i < n;++i) 669 if(LT(Distance(peg,Line(vert[i],vert[(i+1)%n])),pr)){ 670 fit = 0; 671 break; 672 } 673 if(fit) cout << "PEG WILL FIT" << endl; 674 else cout << "PEG WILL NOT FIT" << endl; 675 } 676 else cout << "PEG WILL NOT FIT" << endl; 677 } 678 679 return 0; 680 }