http://poj.org/problem?id=2079
大意:在一堆点中寻找三个点,能围成面积最大的三角形。
分析:可以想象最大的三角形一定是凸包上的点围成的。(反证法,想想。。)
接下来是求解最大的面积。简单的做法是直接来个n^3枚举,这应该会超时。再一次利用凸多边形的凸性,旋转卡壳。
寻找最大的三角形,先是两个点不动,接着点3个点不断在凸包上跑动,到最大三角形的位置时,更新最大面积。三个顶点均这样更新,多边形变回原来的形状时,变化一个点,另外两个点都会因此受到影响,这样持续下去,完成一个大循环。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
const int N=5e4+10;
struct point{
int x,y;
}p[N];
int cross(point p0,point p1,point p2){
return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);
}
int dis2(point p1,point p2){
return (p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y);
}
int cmp1(point p1,point p2){
return p1.x<p2.x||(p1.x==p2.x&&p1.y<p2.y);
}
int cmp2(point p1,point p2){
int c=cross(p[0],p1,p2);
if(c==0) return dis2(p[0],p1)<dis2(p[0],p2);
return c>0;
}
int top;
point sta[N];
void convex(int n){
top=0;
sort(p,p+n,cmp1);
sort(p+1,p+n,cmp2);
sta[top++]=p[0];
sta[top++]=p[1];
for(int i=2;i<n;i++){
if(cross(sta[top-2],sta[top-1],p[i])>0) sta[top++]=p[i];
else {
top--;
while(top>=2&&cross(sta[top-2],sta[top-1],p[i])<=0) top--;
sta[top++]=p[i];
}
}
}
int rotating(){ //利用凸多边形的凸性,固定两个点,第三个点变
int ans=0; //转一圈就能找完
sta[top]=sta[0];
int i=0,j=1,k=2;
while(k!=0){
int ii=i,jj=j,kk=k,temp;
while((temp=cross(sta[i],sta[j],sta[k]))<cross(sta[i],sta[j],sta[k+1])){
k=k+1; if(k>=top) k=0;
}
ans=max(ans,temp);
while((temp=cross(sta[i],sta[j],sta[k]))<cross(sta[i],sta[j+1],sta[k])){
j=j+1; if(j>=top) j=0;
}
ans=max(ans,temp);
while((temp=cross(sta[i],sta[j],sta[k]))<cross(sta[i+1],sta[j],sta[k])){
i=i+1; if(i>=top) i=0;
}
ans=max(ans,temp);
if(i==ii&&j==jj&&k==kk) k=(k+1)%top; //回到原来的形状,k+1,k==0时跳出
}
return ans;
}
int main()
{
//freopen("cin.txt","r",stdin);
int n;
while(cin>>n&&(n!=-1)){
for(int i=0;i<n;i++){
scanf("%d%d",&p[i].x,&p[i].y);
}
if(n<3) {
puts("0.00");
continue;
}
convex(n);
printf("%.2lf\n",rotating()/2.0);
}
return 0;
}