zoukankan      html  css  js  c++  java
  • 【POJ2187】Beauty Contest-凸包+旋转卡壳

    测试地址:Beauty Contest

    题目大意:平面上有N(N≤50000)个点,输出这些点之间最大的距离的平方。

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

    我们很容易想到枚举所有点对,然后求距离最大值,然而这是O(N^2)的,对于这一题是不行的,那么怎么办呢?

    有一个显而易见的结论:平面上最远点对一定在它们的凸包上。我们可以求出凸包,然后对于凸包上的顶点枚举,然而凸包上的点也有可能达到50000个,这时候就要用到旋转卡壳了。旋转卡壳的模板我是按这个的思想写的。这时候又有一个显而易见的结论:平面上最远点对一定是对踵点对,而对踵点对的数量可以证明是不超过3N/2的,这就保证了算法的复杂度为O(N),结合求凸包的O(NlogN),总时间复杂度为O(NlogN),可以通过全部数据(而且很快)。

    以下是本人代码:

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


  • 相关阅读:
    SimpleAdapter的用法
    ListView中加载大量的图片
    用PreferenceActivity做一个标准的设置界面
    用代码构造PreferenceScreen
    工具类之Condition
    工具类之Mutex
    Linux初探之如何查看帮助文档自学命令[网址]
    linux基础之帮助文档---常用的命令[转载]
    Linux 下常见的四款chm查看器比较[转载+亲测可用]
    Linux(Ubuntu)下MySQL的安装与配置[转载+亲测]
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793704.html
Copyright © 2011-2022 走看看