bzoj 1069: [SCOI2007]最大土地面积

Description

在某块平面土地上有N个点,你可以选择其中的任意四个点,将这片土地围起来,当然,你希望这四个点围成的多边形面积最大。

Input

第1行一个正整数N,接下来N行,每行2个数x,y,表示该点的横坐标和纵坐标。

Output

最大的多边形面积,答案精确到小数点后3位。

Sample Input

5
0 0
1 0
1 1
0 1
0.5 0.5

Sample Output

1.000

HINT

数据范围 n<=2000, |x|,|y|<=100000


想摔键盘。。无论如何都像摔键盘。调了整整三个小时。最后随手把叉积算面积比较的>改成>=竟然就过了。。过了。。了【摔】

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

这题我们先算出凸包。然后就好办了。枚举对角线上两个点。我们可以发现另外两个点是单调的。可以直接求出来。然后复杂度就是O(n^2)的了

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

刚刚又想了一下。。不加等号是不是会卡在某个点而不往后推进。。【雾】

#include<cmath>
#include<cstdio>
#include<algorithm>
using namespace std;
struct points
{
     double x,y;
}a[5001],chs[5001];
inline double max(double x,double y)
{
     if(x>y)
          return x;
     return y;
}
inline double xabs(double x)
{
     if(x<0)
          x=-x;
     return x;
}
inline double dis(points x,points y)
{
     return sqrt((x.x-y.x)*(x.x-y.x)+(x.y-y.y)*(x.y-y.y));
}
inline double multi(points p0, points p1, points p2)
{
     return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);
}
inline bool cmp(points x,points y)
{
     if(multi(x,y,a[1])>0)
          return true;
     if(multi(x,y,a[1])==0&&dis(x,a[1])<dis(y,a[1]))
          return true;
     return false;
}
int main()
{
	// freopen("land.in","r",stdin);
//	 freopen("land.out","w",stdout);
     int n;
     scanf("%d",&n);
     int i;
     for(i=1;i<=n;i++)
          scanf("%lf%lf",&a[i].x,&a[i].y);
     double minx=2100000000,miny=2100000000;
     int d=0;
     for(i=1;i<=n;i++)
     {
          if(a[i].y<miny)
          {
          	   minx=a[i].x;
               miny=a[i].y;
               d=i;
          }
          else if(a[i].y==miny)
          {
               if(a[i].x<minx)
               {
                    minx=a[i].x;
                    d=i;
               }
          }
     }
     points t;
     t=a[d];
     a[d]=a[1];
     a[1]=t;
     sort(a+2,a+1+n,cmp);
     int sp=1,k=2;
     chs[0]=a[n];
     chs[1]=a[1];
     while(k<=n)
     {
          double x=multi(chs[sp],chs[sp-1],a[k]);
          if(x<=0)
          {
               sp++;
               chs[sp]=a[k];
               k++;
          }
          else
               sp--;
     }

     //printf("%d\n",sp);

     
     int p1,p2,p3;
     double ans=0;




     for(i=sp+1;i<=2*sp;i++)
          chs[i]=chs[i-sp];
     for(i=1;i<=sp;i++)
     {
          p1=i+2;
          p2=i+1;
          p3=p1+1;
          while(p1-i!=sp)
          {
          	   while(p2+1!=p1&&xabs(multi(chs[i],chs[p1],chs[p2+1]))>=xabs(multi(chs[i],chs[p1],chs[p2])))
          	        p2++;
          	   while(p3+1-i<=sp&&xabs(multi(chs[i],chs[p1],chs[p3+1]))>=xabs(multi(chs[i],chs[p1],chs[p3])))
          	        p3++;
               ans=max(xabs(multi(chs[i],chs[p1],chs[p2]))+xabs(multi(chs[i],chs[p1],chs[p3])),ans);
  //             if(ans>900000000)
    //                ans=0;
			   p1=p1+1;
			   if(p3<=p1)
			        p3=p1+1;
          }
     }
     printf("%.3lf\n",ans/double(2));
     return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值