【BZOJ4445】【SCOI2015】小凸想跑步 半平面交
用半平面交计算可行区域面积,除以总面积,得到概率。
假设当前站位的坐标为p(x,y),根据三角形面积最小,建立不等式关系。
1 #include <iostream> 2 #include <cstdlib> 3 #include <cstdio> 4 #include <cmath> 5 #include <algorithm> 6 7 using namespace std; 8 9 const int N = 400000 + 5; 10 const double eps = 1e-8; 11 12 inline int sgn(double x) { 13 return (x > eps) - (x < -eps); 14 } 15 struct Point { 16 double x, y; 17 Point(double x = 0, double y = 0): x(x), y(y) {} 18 void read() { 19 scanf("%lf%lf", &x, &y); 20 } 21 void write() { 22 printf("%.2lf %.2lf\n", x, y); 23 } 24 Point operator + (const Point &t)const { 25 return Point(x + t.x, y + t.y); 26 } 27 Point operator - (const Point &t)const { 28 return Point(x - t.x, y - t.y); 29 } 30 double operator * (const Point &t)const { 31 return x * t.x + y * t.y; 32 } 33 double operator ^ (const Point &t)const { 34 return x * t.y - y * t.x; 35 } 36 } P[N], poly[N]; 37 #define Cross(a,b) ((a)^(b)) 38 struct Line { 39 Point s, v; 40 double ang; 41 Line() {} 42 Line(Point s, Point v): s(s), v(v) { 43 ang = atan2(v.y, v.x); 44 } 45 bool operator < (const Line &t)const { 46 if (sgn(ang - t.ang) != 0) return ang < t.ang; 47 return Cross(s - t.s, t.v) < 0; 48 } 49 Point operator & (const Line &t)const { 50 double a = Cross(t.s - s, t.v); 51 double b = Cross(v, t.v); 52 Point ret = s; 53 ret.x += v.x * a / b; 54 ret.y += v.y * a / b; 55 return ret; 56 } 57 } L[N], Q[N]; 58 59 double Area(Point *P, int n) { 60 double area = 0; 61 for (int i = 1; i <= n; i ++) 62 area += Cross(P[i], P[i % n + 1]); 63 return area * 0.5; 64 } 65 void HPI(Line *L, int n, int &cnt) { 66 sort(L + 1, L + 1 + n); 67 int l = 1, r = 2, m = 1; 68 for (int i = 2; i <= n; i ++) 69 if (fabs(L[i].ang - L[i - 1].ang) > eps) 70 L[++m] = L[i]; 71 Q[1] = L[1], Q[2] = L[2]; 72 for (int i = 3; i <= m; i ++) { 73 if (sgn(Q[r].v ^ Q[r - 1].v) == 0) return; 74 if (sgn(Q[l].v ^ Q[l + 1].v) == 0) return; 75 while (l < r && Cross((Q[r]&Q[r - 1]) - L[i].s, L[i].v) > eps) --r; 76 while (l < r && Cross((Q[l]&Q[l + 1]) - L[i].s, L[i].v) > eps) ++l; 77 Q[++r] = L[i]; 78 } 79 while (l < r && Cross((Q[r]&Q[r - 1]) - Q[l].s, Q[l].v) > eps) --r; 80 while (l < r && Cross((Q[l]&Q[l + 1]) - Q[r].s, Q[r].v) > eps) ++l; 81 if (r - l <= 1) return; 82 Q[r + 1] = Q[l]; 83 cnt = 0; 84 for (int i = l; i <= r; i ++) 85 poly[++cnt] = Q[i] & Q[i + 1]; 86 } 87 88 /* 89 a*x + b*y + c < 0 90 (x-x1)*(y2-y1)-(y-y1)*(x2-x1) < (x-x3)*(y4-y3)-(y-y3)*(x4-x3) 91 (y2-y1)*x-(y4-y3)*x - (x2-x1)*y+(x4-x3)*y - (y2-y1)*x1+(x2-x1)*y1+(y4-y3)*x3-(x4-x3)*y3 < 0 92 */ 93 void init(int n, int &cnt) { 94 cnt = 0; 95 Point s, v; 96 double x1 = P[1].x, x2 = P[2].x; 97 double y1 = P[1].y, y2 = P[2].y; 98 for (int i = 2; i <= n; i ++) { 99 double x3 = P[i].x, x4 = P[i + 1].x; 100 double y3 = P[i].y, y4 = P[i + 1].y; 101 double a = (y2 - y1) - (y4 - y3); 102 double b = (x4 - x3) - (x2 - x1); 103 double c = -x1 * y2 + x2 * y1 + x3 * y4 - x4 * y3; 104 v = Point(b, -a); 105 if (sgn(a)) s = Point(-c / a, 0); 106 else s = Point(0, -c / b); 107 L[++cnt] = Line(s, v); 108 } 109 for (int i = 1; i <= n; i ++) 110 L[++cnt] = Line(P[i], P[i + 1] - P[i]); 111 } 112 113 int n, m, k; 114 void data() { 115 scanf("%d", &n); 116 for (int i = 1; i <= n; i ++) P[i].read(); 117 P[n + 1] = P[1]; 118 } 119 int main() { 120 data(); 121 init(n, k); 122 HPI(L, k, m); 123 double a = Area(poly, m); 124 double b = Area(P, n); 125 printf("%.4lf\n", fabs(a / b)); 126 return 0; 127 }