题面
解析
设凸包的0,1号点为A(x1,y1),B(x2,y2),在剩余点中任取两个相邻点C(x3,y3),D(x4,y4),满足点D对应的点的编号大于点C对应的点的编号,再设凸包中可选点为P(x,y)
由叉积求面积公式得:
(x1-x) * (y2-y) - (x2-x) * (y1-y) < (x3-x) * (y4-y) - (x4-x) * (y3-y)
(这里求面积不用加绝对值,逆时针计算叉积,这里一定为正)
化简得:
(y1-y2-y3+y4) * x + (-x1+x2+x3-x4) * y + x1*y2 - x2 * y1 - x3 * y4 + x4 * y3 < 0
令A = y1-y2-y3+y4, B = -x1+x2+x3-x4, C = x1*y2 - x2 * y1 - x3 * y4 + x4 * y3
原不等式变为 Ax + By + C < 0
可以联想到线性规划, 即半平面交
再考虑,如何将不等式转化为向量,并且满足向量的左半平面是可行域
这个可以自己画一画,发现无论A,B为正或负,当该直线的方向向量为( -B, A)时,满足要求
向量起点为便于计算可以取直线与任一坐标轴交点,注意特判直线与该坐标轴是否有交点,没有则取直线与另一坐标轴交点
把原凸包的所有边和用该不等式构造出的边加入坐标系,跑一下半平面交的模板就可以了
代码:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<cstdio> 2 #include<cmath> 3 #include<algorithm> 4 using namespace std; 5 const int maxn = 200005 ; 6 const double eps = 1e-13; 7 8 int n, tot, L, R; 9 struct point{ 10 double xx, yy; 11 }p[maxn], a[maxn]; 12 13 struct line{ 14 double deg; 15 point u, v; 16 void Mak(int x,int y) 17 { 18 u = p[x]; 19 v = p[y]; 20 deg = atan2(p[y].yy - p[x].yy, p[y].xx - p[x].xx); 21 } 22 }xl[maxn], qu[maxn]; 23 24 double Cp(point x, point y) 25 { 26 return (double)(x.xx * y.yy) - (x.yy * y.xx); 27 } 28 29 bool cmp(line x, line y) 30 { 31 if(fabs(x.deg - y.deg) >= eps) 32 return x.deg < y.deg; 33 point p = (point){y.v.xx - x.u.xx, y.v.yy - x.u.yy}, q = (point){x.v.xx - x.u.xx, x.v.yy - x.u.yy}; 34 return Cp(p, q) < 0; 35 } 36 37 point Getpoint(line a, line b) 38 { 39 double a1 = a.u.yy - a.v.yy, b1 = a.v.xx - a.u.xx, c1 = a.u.xx * a.v.yy - a.v.xx * a.u.yy; 40 double a2 = b.u.yy - b.v.yy, b2 = b.v.xx - b.u.xx, c2 = b.u.xx * b.v.yy - b.v.xx * b.u.yy; 41 return (point){(c1*b2-c2*b1)/(a2*b1-a1*b2), (a2*c1-a1*c2)/(a1*b2-a2*b1)}; 42 } 43 44 bool check(point x, line y) 45 { 46 double z = Cp((point){y.v.xx - y.u.xx, y.v.yy - y.u.yy}, (point){x.xx - y.u.xx, x.yy - y.u.yy}); 47 return z < 0.0; 48 } 49 50 int deq[maxn]; 51 52 void SI() 53 { 54 sort(xl + 1, xl + tot + 1, cmp); 55 int cnt = 0; 56 for(int i = 1 ; i < tot ; ++i) 57 if(fabs(xl[i].deg - xl[i+1].deg) >= eps) 58 qu[++cnt] = xl[i]; 59 qu[++cnt] = xl[tot]; 60 L = 1;R = 2; 61 deq[1] = 1;deq[2] = 2; 62 for(int i = 3; i <= cnt ; ++i) 63 { 64 while(L < R && check(Getpoint(qu[deq[R]], qu[deq[R-1]]), qu[i])) R--; 65 while(L < R && check(Getpoint(qu[deq[L]], qu[deq[L+1]]), qu[i])) L++; 66 deq[++R] = i; 67 } 68 while(L < R && check(Getpoint(qu[deq[R]], qu[deq[R-1]]), qu[deq[L]])) R--; 69 while(L < R && check(Getpoint(qu[deq[L]], qu[deq[L+1]]), qu[deq[R]])) L++; 70 } 71 72 double Size_big() 73 { 74 double ret = 0.0; 75 for(int i = 1; i <= n ;++i) 76 ret += Cp(p[i], p[i+1]); 77 return fabs(ret); 78 } 79 80 double Size_small() 81 { 82 double ret = 0.0; 83 int res = 0; 84 deq[R + 1] = deq[L]; 85 for(int i = L ; i <= R; ++i) 86 a[++res] = Getpoint(qu[deq[i]], qu[deq[i + 1]]); 87 for(int i = 1; i < res ; ++i) 88 ret += Cp(a[i], a[i + 1]); 89 ret += Cp(a[res], a[1]); 90 return fabs(ret); 91 } 92 93 int main() 94 { 95 scanf("%d",&n); 96 tot = n; 97 for(int i = 1; i <= n ; ++i) 98 scanf("%lf%lf", &p[i].xx, &p[i].yy); 99 p[n + 1] = p[1]; 100 double S = Size_big(); 101 for(int i = 1; i <= n ; ++i) 102 xl[i].Mak(i, i + 1); 103 for(int i = 2 ; i <= n ; ++i) 104 { 105 double A = p[1].yy - p[i].yy - p[2].yy + p[i + 1].yy; 106 double B = p[2].xx - p[i + 1].xx - p[1].xx + p[i].xx; 107 double C = Cp (p[1], p[2]) - Cp (p[i], p[i + 1]); 108 xl[++tot].u.xx = B ? 0.0 : -C / A; 109 xl[tot].u.yy = B ? -C / B : 0.0; 110 xl[tot].v = (point) {xl[tot].u.xx - B, xl[tot].u.yy + A}; 111 xl[tot].deg = atan2(xl[tot].v.yy - xl[tot].u.yy, xl[tot].v.xx - xl[tot].u.xx); 112 } 113 SI(); 114 double s = Size_small(); 115 116 printf("%.4lf", s / S); 117 return 0; 118 }