zoukankan      html  css  js  c++  java
  • poj 2079 Triangle (二维凸包旋转卡壳)

    Time Limit: 3000MS   Memory Limit: 30000KB   64bit IO Format: %I64d & %I64u
    Submit Status

    Description

    Given n distinct points on a plane, your task is to find the triangle that have the maximum area, whose vertices are from the given points.

    Input

    The input consists of several test cases. The first line of each test case contains an integer n, indicating the number of points on the plane. Each of the following n lines contains two integer xi and yi, indicating the ith points. The last line of the input is an integer −1, indicating the end of input, which should not be processed. You may assume that 1 ≤ n ≤ 50000 and −10^4 ≤ xi, yi ≤ 10^4 for all i = 1 . . . n.

    Sample Input
    3
    3 4
    2 6
    2 7
    5
    2 6
    3 9
    2 0
    8 0
    6 5
    -1
    

    Output

    For each test case, print a line containing the maximum area, which contains two digits after the decimal point. You may assume that there is always an answer which is greater than zero.

    Sample output
    0.50
    27.00
    题意:给出N个点,从中选出3个点,使其面积达到最大。
    题解:我们知道这三个点肯定在凸包上,我们求出凸包之后不能枚举,因为题目n比较大,枚举的话要O(n^3)的数量级,所以采用旋转卡壳的做法:
    首先确定i,j,对k进行循环,知道找到第一个k使得cross(i,j,k)>cross(i,j,k+1),如果k==i进入下一次循环。
    对j,k进行旋转,每次循环之前更新最大值,然后固定一个j,同样找到一个k使得cross(i,j,k)>cross(i,j,k+1)。对j进行++操作,继续进行下一次,
    直到j==k为止。
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #define MAX 50010
    using namespace std;
    struct Point{
        double x,y;
        Point(double x=0,double y=0):x(x),y(y){}
    };
    Point P[MAX],ch[MAX];
    typedef Point Vector;
    Vector operator - (Point A,Point B)
    {
        return Vector(A.x-B.x,A.y-B.y);
    }
    bool operator <(const Point &a,const Point &b)
    {
        return a.x<b.x||(a.x==b.x&&a.y<b.y);
    }
    double Cross(Vector A,Vector B)
    {
        return A.x*B.y-A.y*B.x;
    }
    int ConvexHull(Point *p,int n)
    {
        sort(p,p+n);
        int m=0;
        for(int i=0;i<n;i++)
        {
            while(m>1&&Cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])<=0) m--;
            ch[m++]=p[i];
        }
        int k=m;
        for(int i=n-2;i>=0;i--)
        {
            while(m>k&&Cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])<=0) m--;
            ch[m++]=p[i];
        }
        if(n>1) m--;
        return m;
    }
    double rotating_calipers(int n)
    {
        double ans=0,tmp;
        int i,j,k,kk;
        n++;
        for(int i=0;i<n;i++)
        {
            j=(i+1)%n;
            k=(j+1)%n;
            while(k!=i&&j!=i)
            {
                while(k!=i&&Cross(ch[i]-ch[j],ch[j]-ch[k])<Cross(ch[i]-ch[j],ch[j]-ch[k+1]))
                k=(k+1)%n;
                tmp=Cross(ch[i]-ch[j],ch[j]-ch[k]);
                ans=max(tmp,ans);
                j=(j+1)%n;
            }
            if(k==i)
                continue;
            /*kk=(k+1)%n; //kk是标记j的 j +1以后 不能是kk 也就是说j不等于k的意思 kk!=j
            //环状的 可以遍历所有情况 一定不会忘了后期的长边的 无需顾虑
            //不存在k到i之间有一个点k0使得ijk0很大 一一对应着都比ijk小
            //为什么j==kk的时候要停止 ik这条边的意义是什么 环状可以遍历所有情况的 ik等到i变成k k变成i的时候j正好是另一半面 得证
         //固定一个顶点 找出对应着这个顶点的area最大的三角形 遍历所有顶点 所以最大的那个三角形会出现三次 while(k!=i&&kk!=j) { tmp=Cross(ch[i]-ch[j],ch[j]-ch[k]); ans=max(tmp,ans); while(k!=i&&Cross(ch[i]-ch[j],ch[j]-ch[k])<Cross(ch[i]-ch[j],ch[j]-ch[k+1])) k=(k+1)%n; j=(j+1)%n; }
    */ } return ans/2; } int main() { int n; while(scanf("%d",&n)&&n!=-1) { for(int i=0;i<n;i++) scanf("%lf%lf",&P[i].x,&P[i].y); int m=ConvexHull(P,n); double ans=rotating_calipers(m); printf("%.2f ",ans); } return 0; }

    //不能像D题poj2187一样枚举边 因为可能三个点 任意两个点不相邻

    //把kk那段代码展开,会让运行时间变少100ms。时限为3000ms

    //关于二维凸包旋转卡壳问题的证明还需加深理解,这道题是环状遍历,一定可以遍历所有情况的。

  • 相关阅读:
    MIP技术进展月报第3期:MIP小姐姐听说,你想改改MIP官网?
    MIP技术进展月报第2期: 数据绑定,异步脚本加速
    WebP 在减少图片体积和流量上的效果如何?MIP技术实践分享
    改造MIP获得搜索青睐,轻松完成SEO
    MIP 技术进展月报:储存功能全新上线,MIP-Cache域名升级,校验更严谨
    【转】W3C中国与百度联合组织移动网页加速技术研讨会
    百度将与W3C中国召开MIP技术研讨会
    【公告】MIP组件审核平台故障-影响说明
    【公告】关于8.8MIP组件审核平台故障的说明
    MIP 移动网页加速器视频教程全新发布
  • 原文地址:https://www.cnblogs.com/Ritchie/p/5507935.html
Copyright © 2011-2022 走看看