• 【POJ2079】Triangle-旋转卡壳


    测试地址:Triangle

    题目大意:平面上有N(N≤50000)个点,要求选出其中的3个点,使得连成的三角形面积最大,求出这个最大面积。

    做法:这题需要用到旋转卡壳。

    首先O(N^3)的枚举肯定是炸的,那么怎么办呢?

    我们可以先求出凸包,可以证明最大的三角形顶点一定是凸包的顶点。然后枚举三角形的其中一个顶点i,然后初始化另两个顶点i,j为j=next[i],k=next[j],首先将找到一点k使得三角形ijk面积最大,然后更新最大面积,再然后将j赋值为next[j],再找到一点k使得三角形ijk面积最大,然后再更新最大面积,如此重复直到j=i。我们可以发现,k是不会往回移动的,所以总复杂度为O(N^2),虽然看上去过不了,但是实测是可以通过全部数据的。

    犯二的地方:要注意枚举的是凸包上的点,以及G++编译器输出实数要使用f而不是lf,被坑了好多遍了总记不住,好气啊。

    以下是本人代码:

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <cmath>
    #define eps 1e-8
    #define inf 1000000000
    using namespace std;
    int n,s[50010],t,next[50010];
    double ans;
    struct point
    {
      double x,y;
      point operator - (point a) const
      {
        point s;
    	s.x=x-a.x;
    	s.y=y-a.y;
    	return s;
      }
    }p[50010];
    
    double dis(point a,point b)
    {
      return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
    }
    
    double multi(point a,point b)
    {
      return a.x*b.y-b.x*a.y;
    }
    
    bool cmp(point a,point b)
    {
      double s=multi(a-p[1],b-p[1]);
      if (fabs(s)>eps) return s>0;
      else return dis(a,p[1])<dis(b,p[1]);
    }
    
    void graham_scan()
    {
      double lx=inf,ly=inf;
      int li;
      for(int i=1;i<=n;i++)
        if (p[i].x<lx||(fabs(p[i].x-lx)<=eps&&p[i].y<ly))
    	{
    	  lx=p[i].x,ly=p[i].y;
    	  li=i;
    	}
      swap(p[1],p[li]);
      sort(p+2,p+n+1,cmp);
      s[1]=1;t=1;
      for(int i=2;i<=n;i++)
      {
        while(t>1&&multi(p[i]-p[s[t-1]],p[s[t]]-p[s[t-1]])>=0) t--;
    	s[++t]=i;
      }
    }
    
    void rotating_calipers()
    {
      for(int i=1;i<t;i++) next[s[i]]=s[i+1];
      next[s[t]]=s[1];
      for(int i=1;i<=t;i++)
      {
        int j=next[s[i]],k=next[j];
    	while(j!=s[i])
    	{
    	  while(k!=s[i]&&multi(p[j]-p[s[i]],p[k]-p[s[i]])<multi(p[j]-p[s[i]],p[next[k]]-p[s[i]])) k=next[k];
    	  ans=max(ans,multi(p[j]-p[s[i]],p[k]-p[s[i]])/2);
    	  j=next[j];
    	}
      }
    }
    
    int main()
    {
      while(scanf("%d",&n)&&n!=-1)
      {
        for(int i=1;i<=n;i++)
    	  scanf("%lf%lf",&p[i].x,&p[i].y);
    	ans=0;
    	graham_scan();
    	rotating_calipers();
        printf("%.2f
    ",ans);
      }
      
      return 0;
    }
    


  • 相关阅读:
    easyui-tree/combotree 子节点前端懒加载(主要解决ie11下加载慢
    解决 Chrome 下表单自动填充问题 (两种方法
    代码编辑器:本地JS文件上传并加载到页面
    PC端使用rem进行屏幕适配
    ECharts 点击非图表区域的点击事件不触发问题
    Angular2+ 使用 Post 请求下载文件
    Express + Element-ui 实现图片/文件上传
    phpMyAdmin -- 没有权限操作用户
    Note of Moment -- 日期处理
    Angular 自定义表单控件 -- CheckboxGroupComponent
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793703.html
Copyright © 2020-2023  润新知