POJ 2079 Triangle(凸包,最大三角形)

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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值