• BZOJ 3707: 圈地


    3707: 圈地

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 236  Solved: 89
    [Submit][Status][Discuss]

    Description

    2维平面上有n个木桩,黄学长有一次圈地的机会并得到圈到的土地,为了体现他的高风亮节,他要使他圈到的土地面积尽量小。圈地需要圈一个至少3个点的多边形,多边形的顶点就是一个木桩,圈得的土地就是这个多边形内部的土地。(因为黄学长非常的神,所以他允许圈出的第n点共线,那样面积算0)

    Input

    第一行一个整数n,表示木桩个数。
    接下来n行,每行2个整数表示一个木桩的坐标,坐标两两不同。

    Output

    仅一行,表示最小圈得的土地面积,保留2位小数。

    Sample Input

    3
    0 0
    0 1
    1 0

    Sample Output

    0.50

    HINT

    对于100%的数据,n<=1000。

    Source

     
    [Submit][Status][Discuss]

    很喵的一道题,据说写个$O(N^{3})$的大暴力就能水过去,黄学长也介绍了一个随机化算法,但出题人还是想了个比较可以接受的正解的。

    简单的说就是给定平面上n个点,求这n个点组成三角形的最小面积。

    如果分别枚举三个点的话是$O(n^{3})$的,时间无法承受。

    如果枚举了两个点a,b。设它们间的距离是L。如果以点a,b所在直线为y轴的话,与其他点所组成的三角形的面积$S=L*|x|/2$,x是其他点在这个坐标系中的横坐标。可以看出面积最小的就是离这个坐标系y轴最近的一个点。如果我们能够快速的得知最近的点的话,就可以将复杂度降低到$O(n^{2})$。

    把这些点两两之间求出一条直线,记录这条直线是哪两个点取到的,记录这条直线的斜率k。然后按照k排序,我们可以依次按照k递增连续变化的顺序处理这些直线。

    首先将这些点按x坐标排序,相当于按x=0直线排序的情况,考虑由两个相邻的斜率k1变到k2时,这个序列的改变只有k1直线的两个点的顺序交换了下,其它点之间的顺序都没变。在枚举直线时,交换两点维护序列即可。

    —— ZRT学长

     1 #include <bits/stdc++.h>
     2 
     3 using namespace std;
     4 
     5 const int mxn = 1005;
     6 
     7 int n, m, p;
     8 
     9 double ans = 1e200;
    10 
    11 struct Pair
    12 {
    13     double x, y;
    14     
    15     inline Pair(void) {};
    16     inline Pair(double a, double b)
    17         : x(a), y(b) {};
    18 }P[mxn];
    19 
    20 inline Pair operator - (const Pair &a, const Pair &b)
    21 {
    22     return Pair(a.x - b.x, a.y - b.y);
    23 }
    24 
    25 struct Line
    26 {
    27     int a, b;
    28     double k;
    29     
    30     inline void set(int i, int j)
    31     {
    32         a = i;
    33         b = j;
    34         
    35         k = (P[i].y - P[j].y) / (P[i].x - P[j].x);
    36     }
    37 }L[mxn * mxn];
    38 
    39 inline bool cmpP(const Pair &a, const Pair &b)
    40 {
    41     if (a.x != b.x)
    42         return a.x < b.x;
    43     else
    44         return a.y < b.y;
    45 }
    46 
    47 inline bool cmpL(const Line &a, const Line &b)
    48 {
    49     return a.k < b.k;
    50 }
    51 
    52 inline double cross(const Pair &a, const Pair &b)
    53 {
    54     return a.x * b.y - a.y * b.x;
    55 }
    56 
    57 int ps[mxn], rk[mxn];
    58 
    59 signed main(void)
    60 {
    61     cin >> n;
    62     
    63     for (int i = 0; i < n; ++i)
    64         cin >> P[i].x >> P[i].y;
    65         
    66     sort(P, P + n, cmpP);
    67     
    68     for (int i = 0; i < n; ++i)
    69         for (int j = 0; j < i; ++j)
    70             L[m++].set(i, j);
    71     
    72     sort(L, L + m, cmpL);
    73     
    74     for (int i = 0; i < n; ++i)
    75         rk[i] = ps[i] = i;
    76     
    77     for (int i = 0; i < m; ++i)
    78     {
    79         int a = L[i].a, b = L[i].b;
    80         
    81         if (ps[a] > ps[b])swap(a, b);
    82         
    83         if (ps[a] > 1 - 1)ans = min(ans, fabs(cross(P[a] - P[b], P[rk[ps[a] - 1]] - P[b])));
    84         if (ps[b] < n - 1)ans = min(ans, fabs(cross(P[a] - P[b], P[rk[ps[b] + 1]] - P[a])));
    85         
    86         swap(ps[a], ps[b]), swap(rk[ps[a]], rk[ps[b]]);
    87     }
    88     
    89     cout << fixed << setprecision(2) << ans / 2.0 << endl;
    90 }

    @Author: YouSiki

  • 相关阅读:
    汉字转拼音的一个类(C#)
    对象当前正在其他地方使用 异常
    关于IE无法打开站点XX已终止操作问题
    C语言有以下几种取整方法:
    做发型屋碰到的
    glTexImage2D()函数的使用注意点
    python爬取百度图片——翻页式网站爬取
    js 中文传值乱码记录
    Wp7 日志 工具
    基于 Android NDK 的学习之旅 Java 方法映射到C中的签名(附源码)
  • 原文地址:https://www.cnblogs.com/yousiki/p/6401194.html
Copyright © 2020-2023  润新知