• Bzoj3707: 圈地


    3707: 圈地

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 276  Solved: 108
    [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。

    /*
        计算几何,,,瞎暴力呗。。。30分
        这题很容易就想到枚举三角形的三个顶点计算面积,不过T成狗
        于是我们转变一下思路,如果我们确定了2个点以后,第三个点有必要去盲目的枚举吗?答案是否定的。实际上我们把经过这两点的线看成一个斜率,把他当成y轴你会发现第三个点明显是在坐标系左右找一个离”y轴”最近的点来算面积更新答案。然后我们可以继续思考,发现我们可以把点按照某个斜率当成”y轴”进行“从左到右”的排序,这样当2点共线的时候,用这两个点的左右2个点去更新答案就好了。也就是说我们采用旋转坐标系的方法,一开始按x坐标排好序,认为直接用竖着的那条斜率,然后维护的话每次其实当两点共线后只要交换他们就能得到斜率转过该事件点的序列。所以我们可以预处理出所有可行的斜率,当成事件点,不断转动坐标系更新答案就好。这样复杂度只有n^2,期望得分100.
    */
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<cstdlib>
    #include<ctime>
    #define inf 1000000000
    #define ll long long
    using namespace std;
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    double ans=1e60;
    int n,tot,id[1000005],a[1000005];
    struct P{
        double x,y;
    }p[1005];
    struct line{
        int x,y;
        double slop;
    }l[1000005];
    double cross(P a,P b){
        return a.x*b.y-a.y*b.x;
    }
    P operator -(P a,P b){
        return (P){a.x-b.x,a.y-b.y};
    }
    bool operator<(P a,P b){
        return a.x<b.x;
    }
    bool operator<(line a,line b){
        return a.slop<b.slop;
    }
    void cal(int i,int j,int k){
        ans=min(ans,abs(cross(p[i]-p[k],p[j]-p[k]))/2);
    }
    int main()
    {
        //freopen("land.in","r",stdin);
        //freopen("land.out","w",stdout);
        n=read();
        for(int i=1;i<=n;i++)
            p[i].x=read(),p[i].y=read();
        sort(p+1,p+n+1);
        for(int i=1;i<=n;i++)id[i]=a[i]=i;
        for(int i=1;i<=n;i++)
            for(int j=i+1;j<=n;j++)
            {
                l[++tot].x=i,l[tot].y=j;//任意两个点求斜率 
                l[tot].slop=(p[j].y-p[i].y)/(p[j].x-p[i].x);
            }
        sort(l+1,l+tot+1);
        for(int i=1;i<=tot;i++)
        {
            int t1=l[i].x,t2=l[i].y;
            if(id[t1]>id[t2])swap(t1,t2);
            if(id[t1]>1)cal(a[id[t1]-1],t1,t2);
            if(id[t2]<n)cal(a[id[t2]+1],t1,t2);
            swap(id[t1],id[t2]);
            swap(a[id[t1]],a[id[t2]]);
        }
        printf("%.2lf",ans);
        return 0;
    }
  • 相关阅读:
    慕课网-安卓工程师初养成-3-2 Java中的算术运算符
    慕课网-安卓工程师初养成-3-1 什么是运算符
    慕课网-安卓工程师初养成-2-13 练习题
    慕课网-安卓工程师初养成-2-12 如何在Java中使用注释
    慕课网-安卓工程师初养成-2-11 Java常量
    慕课网-安卓工程师初养成-2-10 Java中的强制类型转换
    试把一个正整数n拆分为若干个
    求解两个给定正整数m、n的最大公约数(m、n)
    统计n!尾部零
    横竖折对称方阵
  • 原文地址:https://www.cnblogs.com/thmyl/p/7403411.html
Copyright © 2020-2023  润新知