[BZOJ]1069 最大土地面积

[BZOJ]1069

题意:

给出平面上的一些点,找出四个点使这四个点围成的面积最大。

题解:

首先这四个点肯定在凸包上(显然。。),所以求出凸包后 n <script type="math/tex" id="MathJax-Element-2">n</script>地枚举一个点,之后利用旋转卡壳求出与这个点相距最远的点,然后枚举所有点找出两边三角形的最大面积取最大即可。

这题主要是板子吧,,背会就好背会就好

代码:

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
//背板子系列之凸包 + 旋转卡壳 
//By sssSSSay
#define eps 1e-8

using namespace std;

const int Maxn = 5010;

struct node {
    double x, y;    
} p[Maxn], g[Maxn];

int n;
double ans;

node operator - (node a, node b) {return (node){a.x - b.x, a.y - b.y};}

node operator + (node a, node b) {return (node){a.x + b.x, a.y + b.y};}

node operator * (node a, double x) {return (node){a.x * x, a.y * x};}

node operator / (node a, double x) {return (node){a.x / x, a.y / x};}

int dcmp(double x) {return fabs(x) < eps ? 0 : (x > 0 ? 1 : -1);}

double cross(node a,node b) {return a.x * b.y - a.y * b.x;}

bool comp(node a, node b) {
    return a.x < b.x || (a.x == b.x && a.y < b.y);
}

double Dot(node a,node b) {return a.x * b.x + a.y * b.y;}

double Len(node a) {return sqrt(Dot(a, a));}

double Dis(node x,node a,node b) {node v1 = b - a, v2 = x - a; return fabs(cross(v1, v2) / Len(v1));}

double Area(node a,node b,node c) {return cross(b - a, c - a) / 2;}

double CalArea(node a,node b,int m) {
    double sum1 = 0,sum2 = 0;
    for(int i = 1; i <= m; ++i) {
        sum1 = max(sum1, Area(g[i], a, b));
        sum2 = min(sum2, Area(g[i], a, b));
    }
    return sum1 + (-sum2);
}

int Gra() {
    sort(p + 1, p + n + 1, comp);
    int m = 0;
    for(int i = 1; i <= n; ++i) {
        while(m > 1 && dcmp(cross(g[m - 1] - g[m - 2], p[i] - g[m - 2])) <= 0) --m;
        g[m++] = p[i];
    }
    int k = m;
    for(int i = n - 1; i >= 1; --i) {
        while(m > k && dcmp(cross(g[m - 1] - g[m - 2], p[i] - g[m - 2])) <= 0) --m;
        g[m++] = p[i];  
    }
    if(n > 1) m--;
//  else m--;
    return m;
}

double RoCa(int m) {
    if(m == 1 || m == 2) return 0;
    int now = 2; double temp = 0;
    g[m + 1] = g[1];

    for(int i = 1; i <= m; ++i) {
        while(dcmp(Dis(g[now], g[i], g[i + 1]) - Dis(g[now + 1], g[i], g[i + 1])) < 0) {
            ++now; if(now == m + 1) now = 1;
//          printf("!");
        }
        //这样找到的是g[i]对应的对踵点g[now] 即距离g[i]最远的点 
        temp = max(temp, CalArea(g[i], g[now], m));
    }
    return temp;
}

int main() {
//  freopen("test.in","r",stdin);
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i) scanf("%lf%lf", &p[i].x, &p[i].y);
    int m = Gra();
    ans = RoCa(m);
    printf("%.3lf\n", ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值