zoukankan      html  css  js  c++  java
  • 【BZOJ3707】圈地 (几何,旋转坐标系)

    【BZOJ3707】圈地 (几何,旋转坐标系)

    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

    题解:

    如果我们确定了2个点以后,第三个点有必要去盲目的枚举吗?答案是否定的。实际上我们把经过这两点的线看成一个斜率,把他当成y轴你会发现第三个点明显是在坐标系左右找一个离”y轴”最近的点来算面积更新答案。然后我们可以继续思考,发现我们可以把点按照某个斜率当成”y轴”进行“从左到右”的排序,这样当2点共线的时候,用这两个点的左右2个点去更新答案就好了。也就是说我们采用旋转坐标系的方法,一开始按x坐标排好序,认为直接用竖着的那条斜率,然后维护的话每次其实当两点共线后只要交换他们就能得到斜率转过该事件点的序列。所以我们可以预处理出所有可行的斜率,当成事件点,不断转动坐标系更新答案就好。这样复杂度只有n^2。

    代码:

    int n;
    struct point {
        ll x, y;
        point() {}
        point(int xx, int yy)
        {
            x = xx; y = yy;
        }
        bool operator < (const point &b)const
        {
            return y < b.y;
        }
        point operator - (const point &b) const
        {
            return point(x - b.x, y - b.y);
        }
        ll operator ^ (const point &b) const
        {
            return x * b.y - b.x * y;
        }
    } a[1010];
    #define eps 1e-6
    struct line {
        int xid, yid;
        double polar;
        line() {}
        line(int xx, int yy)
        {
            xid = xx; yid = yy;
            polar = atan2(a[yy].y - a[xx].y, a[yy].x - a[xx].x);
        }
        bool operator < (const line &b) const
        {
            return polar < b.polar;
        }
    };
    std::vector<line> v;
    ll ans = 1e18;
    ll cal(int i, int j, int k)
    {
        return abs((a[i] - a[j]) ^ (a[i] - a[k]));
    }
    int id[maxn];
    int info[maxn];
    int main()
    {
    #if DEBUG_Switch
        freopen("D:\code\input.txt", "r", stdin);
    #endif
        //freopen("D:\code\output.txt","w",stdout);
        n = readint();
        repd(i, 1, n) {
            a[i].x = readint();
            a[i].y = readint();
        }
        sort(a + 1, a + 1 + n);
        repd(i, 1, n) {
            repd(j, i + 1, n) {
                v.push_back(line(i, j));
            }
            id[i] = info[i] = i;
        }
        sort(ALL(v));
        for (auto l : v) {
            int t1 = l.xid;
            int t2 = l.yid;
    //        cout<<t1<<" "<<t2<<endl;
            if (id[t1] > id[t2]) {
                swap(t1, t2);
            }
            if (id[t1] > 1) {
                ans = min(cal(info[id[t1] - 1], t1, t2), ans);
            }
            if (id[t2] < n) {
                ans = min(cal(info[id[t2] + 1], t1, t2), ans);
            }
            swap(id[t1], id[t2]);
            info[id[t1]]=t1;
            info[id[t2]]=t2;
        }
        printf("%.2f
    ", 0.5 * ans );
        return 0;
    }
    
    
    本博客为本人原创,如需转载,请必须声明博客的源地址。 本人博客地址为:www.cnblogs.com/qieqiemin/ 希望所写的文章对您有帮助。
  • 相关阅读:
    RPD Volume 168 Issue 4 March 2016 评论1
    初步接触CERNVM
    java中重载与重写的区别
    第三节 java 函数
    第二节 java流程控制(循环结构)
    第二节 java流程控制(判断结构+选择结构)
    JAVA 对象引用,以及对象赋值
    Java学习笔记整理第一章 java基本数据类型、修饰符、运算符
    plantuml的使用
    力扣 第210题
  • 原文地址:https://www.cnblogs.com/qieqiemin/p/13858983.html
Copyright © 2011-2022 走看看