POJ 2079 Triangle 旋转卡壳

16 篇文章 0 订阅
4 篇文章 0 订阅

题目大意

给出平面上的一些点,求这些点能够组成的最大面积三角形。

思路

虽然数据范围有50W,但是POJ上的数据一向很弱,discuss中居然有人这样说:

手动二分发现极限数据凸包上有2596个点
RT
好水的数据

好吧,留给我们的就剩下 O(n2) 的时间内解决这个题了。
首先先求出凸包,之后可以枚举这个大三角形的一条边,然后枚举另一个顶点。很显然这个过程是 O(n3) 的。显然用旋转卡壳优化一下可以到 O(n2) 了。

CODE

#define _CRT_SECURE_NO_WARNINGS

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 50010
using namespace std;

struct Point{
    double x,y;

    Point(double _, double __):x(_),y(__) {}
    Point() {}
    bool operator <(const Point &a)const {
        if(x == a.x)    return y > a.y;
        return x < a.x;
    }
    Point operator +(const Point &a)const {
        return Point(x + a.x,y + a.y);
    }
    Point operator -(const Point &a)const {
        return Point(x - a.x,y - a.y);
    }
    Point operator *(double a)const {
        return Point(x * a,y * a);
    }
    void Read() {
        scanf("%lf%lf", &x, &y);
    }
}point[MAX], stack[MAX];
int top;

inline double Cross(const Point &p1,const Point &p2)
{
    return p1.x * p2.y - p1.y * p2.x;
}

inline void Add(const Point &p,int bottom)
{
    while(top > bottom && Cross(p - stack[top - 1], stack[top] - stack[top - 1]) >= 0)
        --top;
    stack[++top] = p;
}

int points;

inline double RotatingCaliper()
{
    double re = .0;
    for(int i = 1; i < top; ++i) {
        int p = i + 1;
        for(int j = i + 1; j <= top; ++j) {
            while(fabs(Cross(stack[j] - stack[i], stack[(p + 1) % top] - stack[j])) > fabs(Cross(stack[j] - stack[i], stack[p] - stack[j])))
                p = (p + 1) % top;
            re = max(re, fabs(Cross(stack[j] - stack[i], stack[p] - stack[j])));
        }
    }
    return re / 2;
}

int main()
{
    while(scanf("%d", &points), points + 1) {
        for(int i = 1; i <= points; ++i)
            point[i].Read();
        sort(point + 1, point + points + 1);
        top = 0;
        stack[++top] = point[1];
        for(int i = 2; i <= points; ++i)
            Add(point[i], 1);
        int temp = top;
        for(int i = points - 1; i; --i)
            Add(point[i], temp);
        --top;
        stack[0] = stack[top];
        printf("%.2lf\n", RotatingCaliper());
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值