POJ 2079 Triangle (平面点最大三角形 凸包+旋转卡壳 推荐)

77 篇文章 8 订阅
22 篇文章 0 订阅
Triangle
Time Limit: 3000MS Memory Limit: 30000K
Total Submissions: 9424 Accepted: 2805

Description

Given n distinct points on a plane, your task is to find the triangle that have the maximum area, whose vertices are from the given points.

Input

The input consists of several test cases. The first line of each test case contains an integer n, indicating the number of points on the plane. Each of the following n lines contains two integer xi and yi, indicating the ith points. The last line of the input is an integer −1, indicating the end of input, which should not be processed. You may assume that 1 <= n <= 50000 and −104 <= xi, yi <= 104 for all i = 1 . . . n.

Output

For each test case, print a line containing the maximum area, which contains two digits after the decimal point. You may assume that there is always an answer which is greater than zero.

Sample Input

3
3 4
2 6
2 7
5
2 6
3 9
2 0
8 0
6 5
-1

Sample Output

0.50
27.00

Source


题目链接:http://poj.org/problem?id=2079


题目大意:平面上给n个点求任意三点能组成的最大三角形面积


题目分析;显然最大三角形的三个顶点都在凸包上(可以通过反证法),求出凸包后枚举两个点,第三个点根据单调性直接逆时针旋转即可,时间复杂度O(n^2),n方可做是因为坐标是整数点且范围到lim的纯净凸包上的点数量在sqrt(lim)附近,画个图就可以看出来,可以让横坐标每次x = x + 1,纵坐标y = y + x + 1,这样算下来,总的点数接近n*(n+1)/2 + n*(n+1)/2 + n = n^2 + 2n,n^2 + 2n < lim => n ~ sqrt(lim),所以总点数也就在200多左右,n^2的旋转卡壳很快就能过。网上很多O(n)的代码都是错的,以下数据总有一组通不过(来自poj discuss)

6
4 -5
6 -2
5 2
-4 5
-6 2
-5 -2
5
-7 0
-5 1
-1 5
-2 8
-8 4
5
0 7
1 5
5 1
8 2
4 8
5
0 -7
4 -8
8 -2
5 -1
1 -5
-1

答案:

38.50
15.00
15.00
15.00

n^2,282ms

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
int const MAX = 5e4 + 5;
int n;

struct POINT {
    int x, y;
}p[MAX], stk[MAX], base;

double getDist(POINT a, POINT b) {
    return sqrt(1.0 * (a.x - b.x) * (a.x - b.x) + 1.0 * (a.y - b.y) * (a.y - b.y));
}

double getCross(POINT p0, POINT p1, POINT p2) {
    return (p1.x - p0.x) * (p2.y - p0.y) - (p2.x - p0.x) * (p1.y - p0.y);
}

bool cmp(POINT p1, POINT p2) {
    if (getCross(base, p1, p2) == 0) {
        return getDist(base, p1) < getDist(base, p2);
    }
    if (getCross(base, p1, p2) > 0) {
        return true;
    }
    return false;
}

void getBase() {
    scanf("%d %d", &p[0].x, &p[0].y);
    base.x = p[0].x;
    base.y = p[0].y;
    int pos = 0;
    for (int i = 1; i < n; i ++) {
        scanf("%d %d", &p[i].x, &p[i].y);
        if (p[i].y < base.y || (p[i].y == base.y && p[i].x < base.x)) {
            base.x = p[i].x;
            base.y = p[i].y;
            pos = i;
        }
    }
    swap(p[0], p[pos]);
}

int main() {
    while (scanf("%d", &n) && n != -1) {
        getBase();
        sort(p + 1, p + n, cmp);
        stk[0] = p[0];
        stk[1] = p[1];
        int top = 1;
        for (int i = 2; i < n; i ++) {
            while (top > 0 && getCross(stk[top - 1], stk[top], p[i]) <= 0) {
                top --;
            }
            stk[++ top] = p[i];
        }
        double ans = 0;
        stk[++ top] = stk[0];
        for (int i = 0; i < top; i ++) {
            int k = 2;
            for (int j = i + 1; j <= top; j ++) {
                while(getCross(stk[i], stk[j], stk[k]) < getCross(stk[i], stk[j], stk[(k + 1) % top])) {
                    k = (k + 1) % top;
                }
                ans = max(ans, 0.5 * getCross(stk[i], stk[j], stk[k]));
            }
        }
        printf("%.2f\n", ans);
    }
}


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值