[SCOI2015]小凸想跑步——半平面交

题面

     bzoj

解析

    设凸包的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

扫描二维码关注公众号,回复: 6778128 查看本文章

可以联想到线性规划, 即半平面交

再考虑,如何将不等式转化为向量,并且满足向量的左半平面是可行域

这个可以自己画一画,发现无论A,B为正或负,当该直线的方向向量为( -B, A)时,满足要求

向量起点为便于计算可以取直线与任一坐标轴交点,注意特判直线与该坐标轴是否有交点,没有则取直线与另一坐标轴交点

把原凸包的所有边和用该不等式构造出的边加入坐标系,跑一下半平面交的模板就可以了

代码:

  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 }
View Code

  

猜你喜欢

转载自www.cnblogs.com/Joker-Yza/p/11145431.html