计算几何 BAPC 14 C itadel Construction (Gym 100526C )

本文介绍了一种算法,通过使用Graham扫描法找出给定点集的最大凸包,并在此基础上寻找由四点构成的最大面积四边形。该算法首先找到最下最左的点作为起点,接着对其他点进行极角排序,去除共线点,最终通过比较不同组合来确定最大面积。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


题目意思是给定n各点,找四个点,使这四个点围成的面积最大。

首先用granham计算最大凸包,然后枚举最大的四边形,但是枚举的时候要注意优化。

可以这么考虑,若使四边形abcd面积最大,一定是ac最长的时候,再找最优的b跟d,凑成abcd。

    #define SIZE 1001  
    struct point_t{  
        llt x,y;  
    }P[SIZE];  
      
    //叉积,OA×OB  
    inline llt cross(point_t const&O,point_t const&A,point_t const&B){  
        llt xoa = A.x - O.x;  
        llt yoa = A.y - O.y;  
        llt xob = B.x - O.x;  
        llt yob = B.y - O.y;  
        return xoa * yob - xob * yoa;  
    }  
      
    //A如果比B更靠下更靠左返回真  
    inline bool isLowLeft(point_t const&A,point_t const&B){  
        return A.y < B.y || ( A.y == B.y && A.x < B.x );  
    }  
      
    //按照对于pO的极角排序,极角相等的距离远的排在前面,因为后面要做一个unique  
    point_t* pO;  
    bool comp4Graham(point_t const&A,point_t const&B){  
        llt t = cross(*pO,A,B);  
        if ( t ) return t > 0LL;  
      
        llt a1 = A.x > pO->x ? A.x - pO->x : pO->x - A.x;  
        llt a2 = B.x > pO->x ? B.x - pO->x : pO->x - B.x;  
        if ( a1 != a2 ) return a1 > a2;  
      
        a1 = A.y > pO->y ? A.y - pO->y : pO->y - A.y;  
        a2 = B.y > pO->y ? B.y - pO->y : pO->y - B.y;  
        return a1 > a2;  
    }  
      
    //相对于pO是否极角相等  
    inline bool isEqPolar(point_t const&A,point_t const&B){  
        return 0LL == cross(*pO,A,B);  
    }  
      
    //Graham求凸包,结果当中没有共线点,起点总是最下最左点  
    int Graham(point_t P[],int n){  
        if ( 1 == n ) return 1;  
      
        //寻找最下最左点  
        point_t *p = min_element(P,P+n,isLowLeft);  
      
        //交换  
        swap(*p,P[0]);  
      
        if ( 2 == n ) return 2;  
      
        //按极角排序,极角相等,距离近的排在前面  
        pO = P;  
        sort(P+1,P+n,comp4Graham);  
      
        //将相对于pO的共线点均剔除,只保留最后一个  
        p = unique(P+1,P+n,isEqPolar);  
        n = p - P;  
      
        //真正的Graham循环  
        int top = 2;  
        for(int i=2;i<n;++i){  
            while( top > 1 && cross(P[top-2],P[top-1],P[i]) <= 0LL )  
                --top;  
            P[top++] = P[i];  
        }  
        return top;  
    }  
      
    int area2( point_t const&p1,point_t const&p2,point_t const&p3){  
        return abs( p2.x*p3.y - p2.x*p1.y - p1.x*p3.y + p1.x*p1.y - p2.y*p3.x  + p2.y*p1.x + p1.y*p3.x - p1.y*p1.x );  
    }  
      
    int main(){  
        int t;scanf("%d",&t);  
        while(t--){  
            int n;scanf("%d",&n);  
            for(int i=0;i<n;++i)scanf("%d%d",&P[i].x,&P[i].y);  
            n = Graham(P,n);  
              
            int a,b,c,d;  
            int ans = -1;  
            for( a = 0;a < n; ++a){  
                b = a;  
                d = a+1;  
                for ( c = a+1; c < n;++c ) {  
                    while( b < c && area2(P[a],P[b+1],P[c]) >= area2(P[a],P[b],P[c]) )  
                        b++;  
                    //while( d < c) d++;  
                    while( d < n-1 && area2(P[a],P[c],P[d+1]) >= area2(P[a],P[c],P[d]) )  
                        d++;  
                    ans = max(ans, area2(P[a],P[b],P[c]) + area2(P[a],P[c],P[d]) );  
                }  
            }  
            if ( ans % 2 ){  
                printf("%d.5\n",ans/2);  
            }else printf("%d\n",ans/2);  
      
      
        }  
        return 0;  
    }  


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值