zoukankan      html  css  js  c++  java
  • 【 2018 南京网络赛】 D. Jerome's House(几何神题 半平面交+三分)

    Jerome just got several large houses as his 18th18^{th}18th birthday gifts. To decorate one of these houses, he intends to place several carpets in his house. The house is so large that he can't find a carpet which can cover the whole house. He'll book three identical cycle carpets with the radius rrr. He is unwilling to fold his carpet. So the carpets can't exceed the house. If the center coordinates of the three carpets are (x1,y1),(x2,y2),(x3,y3)(x1,y1),(x2,y2),(x3,y3)(x1,y1),(x2,y2),(x3,y3). w1=x1(y2−y3)w1=x1(y2-y3)w1=x1(y2y3) is the value of the first carpet. w2=x2(y3−y1)w2=x2(y3- y1)w2=x2(y3y1) is the second one's value. And w3=x3∗(y1−y2)w3=x3*(y1-y2)w3=x3(y1y2) is the third one's. He will pay ∣w1+w2+w3∣|w1+w2+w3|w1+w2+w3∣ for these carpets. Jerome is so rich that he wants to maximize his cost. You can just consider this house as a CONVEX polygon.

    Input

    One integer T(0<T≤30)T (0<Tle 30)T(0<T30) in the first line. Indicate the number of the test cases.

    In every case:

    Two integers in the first line n,r(3≤n≤1000,0<r<1000)n, r (3 le n le 1000,0 <r<1000)n,r(3n1000,0<r<1000). Indicate the number of vertexes of the polygon and the radius mentioned above.

    nnn pairs of integers <x,y>(0≤∣x∣,∣y∣≤50000)<x, y>(0 le |x|,|y| le 50000)<x,y>(0x,y50000) in next nnn lines. Indicate the vertexes of the polygon.

    Coordinates of all vertexes are different, and adjacent walls of the room are not collinear.

    The vertexes are listed in clockwise order.

    Output

    TTT lines, output the maximum cost Jerome can pay in each line.

    The input data guarantees that the cost is more than 000.

    Let the maximum cost is AAA, and your answer's cost is BBB. Your answer will be considered as correct if and only if ∣(A−B)∣≤10−4|(A -B)| le 10^{-4}(AB)104.

    本题答案不唯一,符合要求的答案均正确

    样例输入

    2
    5 2
    -2 0
    -5 3
    0 8
    7 3
    5 0
    4 1
    0 0
    0 3
    3 3
    3 0

    样例输出

    17.7154
    1.0000



    solution:

    先确定合法的范围,也就是所有的线都向自己的法线方向内缩半径的长度
    题目的给的式子其实就是三角形面积的2倍
    我们把所的直线的半平面交求出来,再求出所有的交点
    也就变成了,在凸包上找三个点使得三角形的面积最大
    可以旋转卡壳,也可以枚举两点,三分第三个点

    CODE:
      1 #include <iostream>
      2 #include <cstdio>
      3 #include <algorithm>
      4 #include <cstring>
      5 #include <vector>
      6 #include <cmath>
      7 using namespace std;
      8 
      9 const double EPS = 1e-6;         //精度系数
     10 
     11 struct Point {
     12     double x, y;
     13     Point(double x = 0, double y = 0) :x(x), y(y) {}
     14     const bool operator < (Point A)const {
     15         return x == A.x ? y < A.y : x < A.x;
     16     }
     17 };  //点的定义
     18 
     19 typedef Point Vector;   //向量的定义
     20 
     21 Vector operator + (Vector A, Vector B) { return Vector(A.x + B.x, A.y + B.y); }    //向量加法
     22 Vector operator - (Vector A, Vector B) { return Vector(A.x - B.x, A.y - B.y); }    //向量减法
     23 Vector operator * (Vector A, double p) { return Vector(A.x*p, A.y*p); }        //向量数乘
     24 
     25 inline int dcmp(double x) {
     26     if (fabs(x) < EPS)return 0; else return x < 0 ? -1 : 1;
     27 }   //与0的关系
     28 
     29 inline double Dot(Vector A, Vector B) { return A.x * B.x + A.y * B.y; }    //向量点乘
     30 inline double Length(Vector A) { return sqrt(Dot(A, A)); }     //向量长度
     31 inline double Cross(Vector A, Vector B) { return A.x*B.y - A.y*B.x; }    //向量叉乘
     32 
     33 struct Line {
     34     Point p;
     35     Vector v;
     36     double ang;
     37     Line(){}
     38     Line(Point p, Vector v) :p(p), v(v) { ang = atan2(v.y, v.x); }
     39     Point point(double t) { return p + v*t; }    //给t值返回点坐标
     40     bool operator < (const Line& L) const {
     41         return ang < L.ang;
     42     }
     43 };  //直线
     44 
     45 // 点 p 在有向直线 L 的左边(线上不算)
     46 
     47 inline bool OnLeft(Line L, Point p) {
     48     return dcmp(Cross(L.v, p - L.p)) > 0;
     49 }
     50 
     51 // 二直线交点。假设交点唯一存在
     52 inline Point GetIntersection(Line a, Line b) {
     53     Vector u = a.p - b.p;
     54     double t = Cross(b.v, u) / Cross(a.v, b.v);
     55     return a.p + a.v * t;
     56 }
     57 
     58 // 半平面交主过程
     59 inline int HalfplaneIntersection(Line *L, int n, Point *poly) {
     60     sort(L, L + n);// 按极角排序
     61 
     62     int first, last;                // 双端队列的第一个元素和最后一个元素的下标
     63     Point *p = new Point[n];        // p[i] 为 q[i] 和 q[i + 1] 的交点
     64     Line *q = new Line[n];          // 双端队列
     65     q[first = last = 0] = L[0];     // 双端队列初始化为只有一个半平面 L[0]
     66     for (int i = 1; i < n; ++i) {
     67         while (first < last && !OnLeft(L[i], p[last - 1])) --last;
     68         while (first < last && !OnLeft(L[i], p[first])) ++first;
     69         q[++last] = L[i];
     70         if (fabs(Cross(q[last].v, q[last - 1].v)) < EPS) {
     71         // 两向量平行且同向
     72             --last;
     73             if (OnLeft(q[last], L[i].p)) q[last] = L[i];
     74         }
     75         if (first < last) p[last - 1] = GetIntersection(q[last - 1], q[last]);
     76     }
     77     while (first < last && !OnLeft(q[first], p[last - 1])) --last;
     78     // 删除无用平面
     79     if (last - first <= 1) return 0;                // 空集
     80     p[last] = GetIntersection(q[last], q[first]);   // 计算首尾两个半平面的交点
     81 
     82     // 从双端队列复制到输出中
     83     int m = 0;
     84     for (int i = first; i <= last; ++i) poly[m++] = p[i];
     85 
     86     delete [] p; delete [] q;
     87     return m;
     88 }
     89 
     90 inline Vector Normal(Vector A) {
     91     double L = Length(A);
     92     return Vector(-A.y / L, A.x / L);
     93 }   //单位法线,左转90°化为单一长度,确保A不是零向量
     94 
     95 const int N = 1024;
     96 
     97 Point input[N], poly[N << 1];
     98 Line lines[N];
     99 
    100 int L, R;
    101 
    102 inline double f(int x) {
    103     Point &A = poly[L], &B = poly[R], &C = poly[x];
    104     return fabs(A.x * B.y - A.x * C.y + B.x * C.y - B.x * A.y + C.x * A.y - C.x * B.y);
    105 }
    106 #define max(a,b) ((a)>=b)?(a):(b);
    107 inline double tri_divide(int l, int r) {
    108     while (l < r - 1) {
    109         int mid = (l + r) >> 1;
    110         int mmid = (mid + r) >> 1;
    111         if (dcmp(f(mid) - f(mmid)) > 0) {
    112             r = mmid;
    113         } else {
    114             l = mid;
    115         }
    116     }
    117     return max(f(l), f(r));
    118 }
    119 
    120 int main() {
    121     int T;
    122     scanf("%d", &T);
    123     while (T--) {
    124         int n;
    125         double ra;
    126         scanf("%d%lf", &n, &ra);
    127         for (int i = 0; i < n; ++i) {
    128             scanf("%lf%lf", &input[i].x, &input[i].y);
    129         }
    130         for (int i = 0; i < n; ++i) {
    131             lines[i] = Line(input[(i + 1) % n], input[i] - input[(i + 1) % n]);
    132         }   // 逆时针构造半平面在左侧的有向直线
    133         for (int i = 0; i < n; ++i) {
    134             lines[i].p = lines[i].p + Normal(lines[i].v) * ra;
    135         }   // 半平面向多边形内缩 r
    136         int m = HalfplaneIntersection(lines, n, poly);
    137             // 半平面交求缩过后的多边形
    138         /*for (int i = m; i < 2 * m; ++i) {
    139             poly[i] = poly[i - m];
    140         }   // 小技巧,复制一遍方便三分*/
    141         // 暴力枚举凸包上的两个点,三分求第三个点使面积最大
    142         double best = 0;
    143         for (int l = 0; l < m - 1; ++l) {
    144             for (int r = l + 1; r < m; ++r) {
    145                 // 第一次三分,[l, r]
    146                 L = l, R = r;
    147                 double tmp = tri_divide(l,r);
    148                 // 第二次三分,[0, l] + [r, n - 1]
    149                 // 由于我们复制了一份多边形顶点序列,上述范围等价于 [r, l + m]
    150                 L = r, R = l + m;
    151                // tmp = max(tmp, tri_divide(L, R));
    152                 best = max(best, tmp);
    153             }
    154         }
    155         printf("%.6f
    ", best);
    156     }
    157 
    158     return 0;
    159 }




  • 相关阅读:
    settTimeout vs setInterval
    JS继承
    JS创建对象
    原型链
    开始学习python的感受
    Problem 29
    Python 查看关键字
    Problem 21
    Problem 34
    Problem 42
  • 原文地址:https://www.cnblogs.com/zhangbuang/p/11146556.html
Copyright © 2011-2022 走看看