题意:求出平面内的点集所组成的面积最大的三角形。
解题思路:考虑凸包+旋转卡壳。面积最大的三角形的三点必定在凸包的顶点上,只不过这里要注意,三角形的边不一定就是凸包的边,有可能三角形相邻两点是横跨凸包的。
关键是如何找三个顶点。这里采用的类似于尺取法,先固定一个点,剩下的两个指针依次逆时针方向旋转,找到最大的面积。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn = 50000;
const double eps = 1e-8;
struct Point
{
double x,y;
}p[maxn],Stack[maxn];
int n,top;
double Cross(Point a,Point b,Point c)
{
return (a.x-c.x)*(b.y-c.y)-(b.x-c.x)*(a.y-c.y);
}
double dis(Point a,Point b)
{
return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
}
int cmp(Point a,Point b)
{
if(Cross(a,b,p[0]) > eps) return 1;
if(fabs(Cross(a,b,p[0])) < eps && dis(b,p[0]) - dis(a,p[0]) < eps) return 1;
return 0;
}
int Graham()
{
sort(p+1,p+n,cmp);
top = 2;
Stack[0] = p[0];
Stack[1] = p[1];
Stack[2] = p[2];
for(int i = 3; i < n; i++){
while(top >= 1 && Cross(p[i],Stack[top],Stack[top-1]) > eps){
top--;
}
Stack[++top]=p[i];
}
return top;
}
double rotating_calipers()//旋转卡壳
{
int i,j=1,k=2;
double ans=0;
Stack[++top]=Stack[0];
for(i=0; i<top; i++)
{
/*边上的两点可以不是凸包上的点,WA无数次*/
while(fabs(Cross(Stack[(k+1)%top],Stack[i],Stack[j])) > fabs(Cross(Stack[k],Stack[i],Stack[j])))
k=(k+1)%top;
while(fabs(Cross(Stack[k],Stack[i],Stack[(j+1)%top])) > fabs(Cross(Stack[k],Stack[i],Stack[j])))
j=(j+1)%top;
ans=max(ans,fabs(Cross(Stack[k],Stack[i],Stack[j])));
}
return ans;
}
int main()
{
while(scanf("%d",&n),n != -1)
{
for(int i = 0; i < n; i++)
scanf("%lf%lf",&p[i].x,&p[i].y);
int k = 0;
for(int i = 1;i < n; i++){
if(p[k].y > p[i].y || (p[k].y == p[i].y) && (p[k].x > p[i].x)){
k=i;
}
}
swap(p[0],p[k]);
Graham();
printf("%.2lf\n",rotating_calipers()/2);
}
return 0;
}