您的位置:首页 > 其它

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

2016-10-04 10:44 531 查看
[align=center]Triangle[/align]

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
Shanghai 2004 Preliminary

题目链接: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);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: