题目给出一个点集,要求其中选三个点能构成的最大三角形的面积。
我的方法是O(n^2),似乎能通过二分降成nlogn,不过好在这题数据不大可以过。
可以证明这三个点必在凸包点中,如果说存在一个面积更大的三角形而它有的点不在凸点上,那么必定可以在凸点上找到一点,使得(替换后)三角形面积更大。
我们先求出凸包,然后在凸点上寻找这三个点即可。寻找过程运用了旋转卡壳思想,固定一条边的跨度,然后寻找最高的顶点。
#include<iostream>
#include<cmath>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=5e4+2;
const double eps=1e-8;
int n;
inline int sgn(double x){
if(fabs(x)<eps) return 0;
else if(x<0) return -1;
else return 1;
}
struct Point{
double x,y;
Point(){
x=0;
y=0;
}
Point(double a,double b):x(a),y(b){}
inline Point operator-(const Point& b)const{
return Point(x-b.x,y-b.y);
}
inline Point operator+(const Point& b)const{
return Point(x+b.x,y+b.y);
}
inline double dot(const Point& b)const{
return x*b.x+y*b.y;
}
inline double cross(const Point&b,const Point& c)const{
return (b.x-x)*(c.y-y)-(c.x-x)*(b.y-y);
}
double operator^(Point a){return x*a.y-y*a.x;}
double operator*(Point a){return x*a.x+y*a.y;}
};
double dist(const Point& a, const Point& b){
return sqrt((b-a).dot(b-a));
}
Point stk[maxn];
Point ps[maxn];
bool operator<(const Point& a,const Point& b){
return a.x<b.x||(a.x==b.x&&a.y<b.y);
}
int Andrew(){ //逆时针扫描
sort(ps,ps+n);
int top=0;
for(int i=0;i<n;i++){
while(top>1&&sgn((stk[top-1]-stk[top-2])^(ps[i]-stk[top-1]))<=0) top--;
stk[top++]=ps[i];
}
int k=top;
for(int i=n-2;i>=0;i--){
while(top>k&&sgn((stk[top-1]-stk[top-2])^(ps[i]-stk[top-1]))<=0) top--;
stk[top++]=ps[i];
}
return top; //凸包点数
}//结果点集逆时针存放在stk中
double rotating_caliper(Point* ps){
double res=0;
int k;
for(int l=1;l<=n/2;l++){ //基边的跨度
k=l+1; //决定三角形高的顶点
for(int i=0;i<n;i++){
while(ps[i].cross(ps[(i+l)%n],ps[k%n])<ps[i].cross(ps[(i+l)%n],ps[(k+1)%n]))
k=(k+1)%n;
res=max(res,ps[i].cross(ps[(i+l)%n],ps[k%n])/2.0);
}
}
return res;
}
int main(){
while(~scanf("%d",&n)&&(~n)){
for(int i=0;i<n;i++){
scanf("%lf%lf",&ps[i].x,&ps[i].y);
}
n=Andrew();
double ans=rotating_caliper(stk);
printf("%.2f\n",ans);
}
return 0;
}