zoukankan      html  css  js  c++  java
  • POJ-2187-Beauty Contest凸包 —— 旋转卡壳

    凸包 —— 旋转卡壳

    POJ-2187-Beauty Contest

    题意:

    给 n 个顶点的坐标,求在这个图中,距离最远的两个点的 距离的平方

    思路:

    距离最远的点,肯定在凸包上,那么先求出凸包,然后直接枚举每两个点的距离(O(n^2))

    旋转卡壳优化:

    先在凸包上找到一条边 A ,并找到距离这条边最远的点 a(最远的两点可能是 A 的某个端点和 a 的距离) ,当逆时针换边 B 的时候,距离最远的点 b 一定不在 a 的顺时针方向,从 a 逆时针找,旋转一周后,找到最大值。(O(n))

    [(img-rwUIPcI9-1587823591390)(C:UsersAdministratorAppDataRoamingTypora	ypora-user-imagesimage-20200425215519845.png)]
    [(img-rwUIPcI9-1587823591390)(C:UsersAdministratorAppDataRoamingTypora ypora-user-imagesimage-20200425215519845.png)]

    注意!!!

    在寻找凸包的时候,当向量×乘为0时,这个点也不能算凸包中的点(只有这样,旋转卡壳才能用),否则只能暴力!

    猜测原因:当暴力的时候,可以跳过这个直线上的点,但是旋转卡壳可能在while循环直接跳出(因为遇到了边上的点,导致边的端点没被遍历到而直接跳出)

    撸代码:

    #include<stdio.h>
    #include<math.h>
    #include<algorithm>
    using namespace std;
    int n;
    struct Point
    {

        int x,y;
    }p[50010];
    int XMUL(Point a,Point b,Point c,Point d)/**ab向量 X cd向量*/
    {
        return ((b.x-a.x)*(d.y-c.y)-(d.x-c.x)*(b.y-a.y));
    }
    int dis(Point a,Point b)
    {
        return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
    }
    bool comp(Point a,Point b)
    {
        int m=XMUL(p[0],a,p[0],b);
        if(m>0)
            return 1;
        else if(m==0&&dis(p[0],a)-dis(p[0],b)<0)
            return 1;
        return 0;
    }
    int main()
    {
        while(~scanf("%d",&n))
        {
            for(int i=0;i<n;i++)
            {
                scanf("%d%d",&p[i].x,&p[i].y);
            }
            /**p0*/
            int k=0;
            for(int i=1;i<n;i++)
            {
                if(p[k].y>p[i].y)
                    k=i;
                else if(p[k].y==p[i].y&&p[k].x>p[i].x)
                    k=i;
            }
            swap(p[k],p[0]);
            /**按照极角坐标排序*/
            sort(p+1,p+n,comp);
            /**求凸包*/
            Point s[50010];
            int top=1;
            s[0]=p[0];
            s[1]=p[1];
            for(int i=2;i<n;i++)
            {
                while(top>=1&&XMUL(s[top-1],s[top],s[top],p[i])<=0)///!!!
                    top--;
                s[++top]=p[i];
            }
            int maxx=0,temp;
            if(top==1)/**特例:只有两个点*/
            {
                printf("%d ",dis(s[0],s[1]));
                continue;
            }
            s[++top]=s[0];/**第一个点放在最后,便于旋转*/
            int j=2;
            for(int i=0;i<top;i++)/**枚举每条边*/
            {
                while(XMUL(s[j],s[i],s[j],s[i+1])<XMUL(s[j+1],s[i],s[j+1],s[i+1]))
                    j=(j+1)%top;/**旋转的是点*/
                maxx=max(maxx,max(dis(s[i],s[j]),dis(s[i+1],s[j])));
            }

            printf("%d ",maxx);
        }
        return 0;
    }
  • 相关阅读:
    Java连接各种数据库的实例
    解决Android SDK Manager 更新、下载慢以及待安装包列表不显示
    This version of the rendering library is more recent than your version of ADT plug-in. Please update
    注册asp.net 4.0 到iis
    linux下常用的截图、录屏工具
    汉化Eclipse+配色方法(官方语言包)
    用了皮肤控件之后,报错:容量超出了最大容量 参数名:capacity
    自定义DateTimeInput(时间)控件的显示格式
    SQL语句增加列、修改列类型、修改列、删除列
    GDI+ DrawString字间距问题
  • 原文地址:https://www.cnblogs.com/HappyKnockOnCode/p/12775669.html
Copyright © 2011-2022 走看看