HDU 3934 Summer holiday(凸包内接最大三角形)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3934

题意:给出n个点,从中找出三个点使得面积最大。

思路:旋转卡壳模板题:首先求凸包,在旋转求最大面积。

#include <iostream>
#include <stdio.h>
#include <cmath>
#include <algorithm>
using namespace std;

struct point
{
    double x,y;

    point(){}
    point(double _x,double _y)
    {
        x=_x;
        y=_y;
    }


    void get()
    {
        scanf("%lf%lf",&x,&y);
    }
};

const double EPS=1e-8;
const int MAX=1000005;
point p[MAX],q[MAX];
int n,m;


int DB(double x)
{
    if(x>EPS) return 1;
    if(x<-EPS) return -1;
    return 0;
}

double Dis(point a,point b)
{
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}

//判断p在向量ab的哪一侧
//右侧:返回正值
//左侧:返回负值
//在向量ab上返回0
double cross(point a,point b,point p)
{
    return (b.x-a.x)*(p.y-a.y)-(b.y-a.y)*(p.x-a.x);
}

int cmp(point a,point b)
{
    double x=Dis(a,p[0]),y=Dis(b,p[0]);
    int flag=DB(cross(p[0],a,b));
    if(flag) return flag==1;
    return DB(x-y)<=0;
}

void Graham(point p[],int n,point q[],int &m)
{
    point temp;
    int i,k=0,a,b;
    for(i=1;i<n;i++)
    {
        a=DB(p[i].y-p[k].y);
        b=DB(p[i].x-p[k].x);
        if(a==-1||!a&&b==-1) k=i;
    }
    if(k!=0) temp=p[0],p[0]=p[k],p[k]=temp;
    sort(p+1,p+n,cmp);
    q[0]=p[0];
    q[1]=p[1];
    p[n]=p[0];
    m=2;
    for(i=2;i<=n;i++)
    {
        while(m>1&&DB(cross(q[m-2],q[m-1],p[i]))<=0) m--;
        q[m++]=p[i];
    }
    m--;
}

double calMaxArea(point q[],int n)
{
    if(n<3) return 0;
    double ans=0,temp;
    int t1=1,t2=2,i;
    q[n]=q[0];
    for(i=0;i<n;i++)
    {
         while(DB(cross(q[t2+1],q[i],q[t1])-(temp=cross(q[t2],q[i],q[t1])))==1)
             t2=(++t2)%n;
         if(DB(temp-ans)==1) ans=temp;
         while(DB(cross(q[t2],q[i],q[t1+1])-(temp=cross(q[t2],q[i],q[t1])))==1)
             t1=(++t1)%n;
         if(DB(temp-ans)==1) ans=temp;
    }
    return ans/2;
}



int main()
{
    while(scanf("%d",&n)!=-1)
    {
        int i;
        for(i=0;i<n;i++) p[i].get();
        Graham(p,n,q,m);
        double ans=calMaxArea(q,m);
        printf("%.2lf\n",ans);
    }
    return 0;
}

  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值