zoukankan      html  css  js  c++  java
  • 武大OJ 706.Farm

    Farmer John has a farm. Betsy, a famous cow, loves running in farmer John's land. The noise she made makes John mad. So he wants to restrict the area Betsy can run. There are nn (4<nle 20000004<n2000000) points of interest (or POI) on the farm, the i-th one located at (x_i,y_i)(xi​​,yi​​), 0le |x_i |,|y_i |le 10^60xi​​,yi​​106​​. So farmer John said: You can select four points, and the area you can run is the convex hull of the four points you select. Betsy is clever, but she doesn't like computing, so she asked you for help to calculate the max area she can run.

    Important note

    There are at most 20 test cases in your input. 18 of them satisify nle 2000n2000. And the ramaining two testcases are generated in random. The max size of input file is about 60MB. Please, use fast input methods (for example, please use BufferedReader instead of Scanner for Java, and scanf instead of cin for C++).

    Input

    Input contains multiple cases, please process to the end of input. The first line of each test cases contains an integer nn, the number of POI. The following nn lines, contains two integers, x_i,y_ixi​​,yi​​, the location of ii-th POI.

    Output

    For each test case, print one line with your answer, your answer should keep exactly one decimal place.

    Sample Input

    4
    0 0
    1 0
    1 1
    0 1
    4
    1 1
    2 2
    3 3
    4 4
    

    Sample Output

    1.0
    0.0


    原题是BZOJ1069

    首先求个凸包,然后在凸包上面枚举两点,找到它两边能组成的最大三角形即可,这个三角形可用2-
    pointer的方式,就是找凸包上关于某一条线最远的点,复杂度是n^2
    n的范围虽然很大,但是n个点都是随机生成的,求凸包后会丢弃大量的点
    求凸包用的是基于水平序的Graham_Scan算法
    需要注意的是求叉积和面积的时候可能会超出int类型,需要转double
    #include<algorithm>
    #include<iostream>
    #include<fstream>
    #include<math.h>
    #include<stdio.h>
    using namespace std;
    
    int n;
    typedef struct{
        int x,y;
    }Point;
    
    Point a[2000005];
    Point b[2000005];
    int q[2000005],top;
    int ans[2000005];
    
    bool cmp(Point a,Point b){
        return a.y<b.y||(a.y==b.y&&a.x<b.x);
    }
    
    //int转double的技巧 
    double cross(int i,int j,int k){
        Point a1=a[i];
        Point b=a[j];
        Point c=a[k];
        return 1.0*(c.x-b.x)*(a1.y-b.y)-1.0*(c.y-b.y)*(a1.x-b.x);
    }
    
    void scan(){
        q[1]=1;q[2]=2;top=2;
        for(int i=3;i<=n;++i)
        {
            while(top>1&&cross(q[top-1],q[top],i)<=0) top--;
            q[++top]=i;
        }
        
        for(int i=1;i<=top;++i)
        ans[i]=q[i];
        ans[0]=top;
        
        
        q[1]=n;q[2]=n-1;top=2;
        for(int i=n-2;i>=1;--i)
        {
            while(top>1&&cross(q[top-1],q[top],i)<=0) top--;
            q[++top]=i;
        }
        
        for(int i=2;i<top;++i)
        {
            ans[0]++;
            ans[ans[0]]=q[i];
        }
    }
    
    //int转double的技巧 
    double area(int i,int j,int k){
        Point a1=a[ans[i]];
        Point b=a[ans[j]];
        Point c=a[ans[k]];
        return fabs((1.0*(c.x-b.x)*(a1.y-b.y)-1.0*(c.y-b.y)*(a1.x-b.x))/2);
    
    }
    
    double max_area=0;
    double left_area=0;
    double right_area=0;
    int main(){
        while(~scanf("%d",&n)){
            max_area=0;
            for(int i=1;i<=n;++i)
            scanf("%d %d",&b[i].x,&b[i].y);
            
            sort(b+1,b+n+1,cmp);
            
            
            
            //去除重复点 
            int len=1;
            a[1]=b[1];
            int i=2;
            while(i<=n)
            {
                while(i<=n&&b[i].x==b[i-1].x&&b[i].y==b[i-1].y) i++;
                if(i<=n)
                a[++len]=b[i];
                i++;
            }
            n=len;
            
            //水平序扫描构造凸包 
            scan();
            
            if(ans[0]<=2) {printf("0.0
    ");continue;}
            if(ans[0]==3) {printf("%.1f
    ",area(1,2,3));continue;}
            
            
            
            int r,l,d;
            for(int i=1;i<=ans[0];++i)
            {
                r=i+1;
                l=i+3;
                if(i+3>ans[0]) continue;//第4个点不应该超过最后一个凸包节点,不然就重复计算了 
                for(int j=i+2;j<=ans[0];++j)
                {
                    if(i==1&&j==ans[0]) continue;
                    
                    while(r+1<j&&area(i,j,r)<=area(i,j,1+r)) r++;
                    right_area=area(i,j,r);
                    
                    while(l+1<=ans[0]&&area(i,j,l)<=area(i,j,l+1)) l++;
                    left_area=area(i,j,l);
                    
                    if(right_area+left_area>max_area) max_area=right_area+left_area;    
                }
            }
            printf("%.1f
    ",max_area);
        
        }
        
    
    
    
    }



  • 相关阅读:
    django regroup的相关知识点
    python学习
    python os的一点心得
    python字符串替换的2种有效方法
    python的缩进格式真的不好吗?
    django的哲学很耐人回味
    python 抓取网页的方法
    分享一点python 编码设置的知识
    python apply的一点知识
    今天休息真舒服
  • 原文地址:https://www.cnblogs.com/noip/p/9517673.html
Copyright © 2011-2022 走看看