• 旋转卡壳-求凸包最大直径


    时间复杂度:O(n)

    参考:https://www.cnblogs.com/xdruid/archive/2012/07/01/2572303.html

    暴力:n^2枚举凸包上的点,如果数据水的话可过。

    高级做法:

    用一对平行线“卡”住凸包进行旋转。

    被一对卡壳正好卡住的对应点对称为对踵点。

    对锺点的具体定义不好说,不过从图上还是比较好理解的(黑色点对)。

    可以证明(此处略过)对踵点的个数不超过3N/2个 也就是说对踵点的个数是O(N)

    对踵点的个数也是我们下面解决问题时间复杂度的保证。

    卡壳呢,具体来说有两种情况:

    1.

    平行线正好卡着两个点

    2.

    平行线分别卡着一条边和两个点

    而第二种情况在实现中比较容易处理,这里就只研究第二种情况。

    在第二种情况中 我们可以看到 一个对踵点和对应边之间的距离比其他点要大

    也就是一个对踵点和对应边所形成的三角形是最大的

    具体实现:

    1.如果qa,qb是凸包上最远两点,必然可以分别过qa,qb画出一对平行线。通过旋转这对平行线,我们可以让它和凸包上的一条边重合,,如图中蓝色直线。可以注意到,qa是凸包上离p和qb所在直线最远的点

    2.于是我们的思路就是枚举凸包上的所有边,对每一条边找出凸包上离该边最远的顶点,计算这个顶点到该边两个端点的距离,并记录最大的值。直观上这是一个O(n2)的算法,和直接枚举任意两个顶点一样了

    3.但是注意到当我们逆时针枚举边的时候,最远点的变化也是逆时针的,这样就可以不用从头计算最远点,而可以紧接着上一次的最远点继续计算于是我们得到了O(n)的算法。

    参考代码:

     1 void rotate()
     2 { 
     3     if(top==2)//注意特殊情况 
     4     {
     5         printf("%d",(int)(dis(s[1],s[2])*dis(s[1],s[2])+eps));
     6         return;
     7     }
     8     s[top+1]=s[1];
     9     int p=3;DB ans=0;
    10     //cross()为叉积函数 
    11     for(int i=1;i<=top;++i)
    12     {
    13         while(cross(s[i],s[i+1],s[p])<cross(s[i],s[i+1],s[p+1])) 
    14         {
    15             p++;p%=top;
    16             if(p==0) p=top;
    17         }//找到距离当前直线最远的点 
    18         DB tmp=max(dis(s[i],s[p]),dis(s[i+1],s[p]));
    19         ans=max(ans,tmp);//更新答案 
    20     }
    21     //ans为最终答案 
    22 }
    View Code

     涉世浅,点染亦浅;历事深,机械亦深。

  • 相关阅读:
    学习笔记9(必做)
    团队作业(四):描述设计
    改进ls的实现(课下作业)
    stat命令的实现-mysate(必做)
    反汇编测试
    学习笔记8(必做)
    初次使用git上传代码到码云
    团队作业(三):确定分工
    学习笔记7(必做)
    缓冲区溢出漏洞实验
  • 原文地址:https://www.cnblogs.com/adelalove/p/8467472.html
Copyright © 2020-2023  润新知