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

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

  • 相关阅读:
    AS2 tween缓动
    flash 绑定 swc类文件
    jsfl自运行与被调运行
    一键清除fla文件中的TLF文本
    as 2的 Event.REMOVED_FROM_STAGE
    jsfl 添加代码
    jsfl 删除库指定内容
    文件上传待研究
    SpringMVC单文件上传、多文件上传、文件列表显示、文件下载
    shiro配置参考(二)可以和mybatis的配置放在一个文件中(不建议这样,可以拆分开来,注意相关配置即可)
  • 原文地址:https://www.cnblogs.com/Ritchie/p/5507935.html
Copyright © 2011-2022 走看看