zoukankan      html  css  js  c++  java
  • [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

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

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

    这个可以自己画一画,发现无论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

      

  • 相关阅读:
    Visio画出的图,裁剪成固定大小再添加马赛克的方法
    单张PPT转成单张PDF的PDF文件怎么设置打印出一页纸有6页PPT
    MVC下载电子表格到本地((导出表格4-4)
    获取配置文件(导出表格4-3)
    获取随机字符串(导出表格4-2)
    ExcelHelper 电子表格帮助类(导出表格4-1)
    二、操作NPOI_从数据库中导出数据到Excel_支持.xls格式
    一、操作NPOI从Excel中导入数据到SqlServer数据库中_xls格式
    Fetch(Promise微队列) 增删改查
    C#获取枚举的描述
  • 原文地址:https://www.cnblogs.com/Joker-Yza/p/11145431.html
Copyright © 2011-2022 走看看