zoukankan      html  css  js  c++  java
  • 【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;
    }
    


  • 相关阅读:
    【JS】 Javascript 入门
    【CSS】 CSS的一些应用实例和参考
    【CSS】 CSS 定位
    【泛泛】 不知道怎么分类的豆知识
    【CSS】 CSS基础知识 属性和选择
    【HTML】 HTML基础知识 表单
    【HTML】 HTML基础知识 一些标签
    【Linux】 文本比较工具 diff和cmp
    php -- or 的用法
    php -- 检查是否存在
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793703.html
Copyright © 2011-2022 走看看