武大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<n\le 20000004<n2000000) points of interest (or POI) on the farm, the i-th one located at (x_i,y_i)(xi​​,yi​​), 0\le |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 n\le 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\n");continue;}
        if(ans[0]==3) {printf("%.1f\n",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\n",max_area);
    
    }
    



}

 




posted on 2018-08-22 14:56  怡红公子  阅读(284)  评论(0编辑  收藏  举报