求点集中面积最大的三角形

如果枚举3个点再算面积,必然超时。

很显然的最大面积的三角形的三个顶点必然是这个点集的凸包上的点,因此先求出凸包。

如果求出凸包仍然枚举,一样会超时。

这个可以借助求凸包直径类似的方法来求最大面积的三角形,使用旋转卡壳方法。

枚举三角形的第一个顶点i,

然后初始第二个顶点j=i+1,第三个顶点k=j+1,

循环k+1直到Area(i,j,k)>Area(i,j,k+1)

更新面积的最大值,下面就开始旋转卡壳了(旋转j,k两个点)

(1)如果Area(i,j,k)

(2)更新面积,j=j+1,如果j=i,跳出循环

这样旋转一圈后,求得的面积就是以i为顶点的最大三角形的面积了。

时间复杂度是O(n^2)

//author:chenkun
//旋转卡壳!
#include <cstdio>
#include <cmath>
 
const int MAXN=50000;
 
struct point {
    int x, y;
} p[MAXN+1],h[MAXN+1];
 
double distance(const point& p1,const point& p2) {
   return sqrt( (p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y));
}
 
double multiply(const point& sp,const point& ep,const point& op) {
      return((sp.x-op.x)*(ep.y-op.y)-(ep.x-op.x)*(sp.y-op.y));
}
 
int partition(point a[],int p,int r) {
    int i=p,j=r+1,k;
    double ang,dis;
    point R,S;
    k=(p+r)/2;
    R=a[p];
    a[p]=a[k];
    a[k]=R;
    R=a[p];
    dis=distance(R,a[0]);
    while(1) {
        while(1) {
            ++i;
            if(i>r) {
                i=r;
                break;
            }
            ang=multiply(R,a[i],a[0]);
            if(ang>0)
                break;
            else if(ang==0) {
                if(distance(a[i],a[0])>dis)
                break;
            }
        }
        while(1) {
             --j;
            if(j<p) {
                j=p;
                break;
            }
            ang=multiply(R,a[j],a[0]);
            if(ang<0)
                break;
            else if(ang==0) {
                if(distance(a[j],a[0])<dis)
                    break;
            }
        }
        if(i>=j)break;
        S=a[i];
        a[i]=a[j];
        a[j]=S;
    }
    a[p]=a[j];
    a[j]=R;
    return j;
}
 
void anglesort(point a[],int p,int r) {
   if(p<r) {
      int q=partition(a,p,r);
      anglesort(a,p,q-1);
      anglesort(a,q+1,r);
   }
}
 
//对PointSet求凸包,点数为n,凸包上的点保存在ch中,点数位len
void Graham_scan(point PointSet[],point ch[],int n,int &len) {
    int i,k=0,top=2;
    point tmp;
    for(i=1;i<n;i++)
        if ( PointSet[i].x<pointSet[k].x ||
            (PointSet[i].x==PointSet[k].x) && (PointSet[i].y<pointSet[k].y) )
               k=i;
    tmp=PointSet[0];
    PointSet[0]=PointSet[k];
    PointSet[k]=tmp;
    anglesort(PointSet,1,n-1);
    if(n<3) {
        len=n;
        for(int i=0;i<n;i++) ch[i]=PointSet[i];
        return ;
    }
    ch[0]=PointSet[0];
    ch[1]=PointSet[1];
    ch[2]=PointSet[2];
    for (i=3;i<n;i++) {
        while (multiply(PointSet[i],ch[top],ch[top-1])>=0) top--;
            ch[++top]=PointSet[i];
    }
    len=top+1;
}
 
double Area(int i,int j,int k) {
    return multiply(h[j],h[k],h[i])/2;
}
 
inline double max(double a,double b){return a>b?a:b;}
int main() {
    int n;
    while(scanf("%d",&n)!=EOF&&n!=-1) {
        for(int i=0;i<n;i++)
            scanf("%d %d",&p[i].x,&p[i].y);
        int len;
        Graham_scan(p,h,n,len);
        //for(int i=0;i<len;i++)
        //    printf("%d %d\n",h[i].x,h[i].y);
 
        double ans=0;
        for(int i=0;i<len;i++) {
            int j=(i+1)%len;
            int k=(j+1)%len;
            while(k!=i&&Area(i,j,k)<area(i,j,(k+1)%len)) {
                k=(k+1)%len;
            }
            if(k==i) continue;
            int kk=(k+1)%len;
            while(j!=kk&&k!=i) {
                ans=max(ans,Area(i,j,k));
                while(k!=i&&Area(i,j,k)<area(i,j,(k+1)%len)) {
                    k=(k+1)%len;
                }
                j=(j+1)%len;
            }
        }
 
        printf("%.2f\n",ans);
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值