• 旋转卡壳法求凸包的直径


    poj 2187

    Beauty Contest
    Time Limit: 3000MS   Memory Limit: 65536K
    Total Submissions: 26545   Accepted: 8184

    Description

    Bessie, Farmer John's prize cow, has just won first place in a bovine beauty contest, earning the title 'Miss Cow World'. As a result, Bessie will make a tour of N (2 <= N <= 50,000) farms around the world in order to spread goodwill between farmers and their cows. For simplicity, the world will be represented as a two-dimensional plane, where each farm is located at a pair of integer coordinates (x,y), each having a value in the range -10,000 ... 10,000. No two farms share the same pair of coordinates. 

    Even though Bessie travels directly in a straight line between pairs of farms, the distance between some farms can be quite large, so she wants to bring a suitcase full of hay with her so she has enough food to eat on each leg of her journey. Since Bessie refills her suitcase at every farm she visits, she wants to determine the maximum possible distance she might need to travel so she knows the size of suitcase she must bring.Help Bessie by computing the maximum distance among all pairs of farms. 

    Input

    * Line 1: A single integer, N 

    * Lines 2..N+1: Two space-separated integers x and y specifying coordinate of each farm 

    Output

    * Line 1: A single integer that is the squared distance between the pair of farms that are farthest apart from each other. 
    求两点间最远距离的平方,枚举会超时

    凸多边形直径

    我们将一个多边形上任意两点间的距离的最大值定义为多边形的直径。 确定这个直径的点对数可能多于一对。 事实上, 对于拥有 n 个顶点的多边形, 就可能有 n 对“直径点对”存在。 

     

    一个多边形直径的简单例子如左图所示。 直径点对在图中显示为被平行线穿过的黑点 (红色的一对平行线). 直径用浅蓝色高亮显示。


    显然, 确定一个凸多边形 P 直径的点对不可能在多边形 P 内部。 故搜索应该在边界上进行。 事实上, 由于直径是由多边形的平行切线的最远距离决定的, 所以我们只需要查询对踵点。 Shamos (1978) 提供了一个 O(n) 时间复杂度计算n点凸包对踵点对的算法。直径通过遍历顶点列表, 得到最大距离即可。 如下是1985年发表于 Preparata 和 Shamos 文章中的 Shamos 算法的伪代码。 
    输入是一个多边形 P={p1,...,pn}. 
    
    此处 Print(p,q) 表示将 (p,q) 作为一个对踵点对输出, Area(p,q,r) 表示三角形 pqr 的有向面积。 虽然直观上看这个过程与常规旋转卡壳算法不同, 但他们在本质上是相同的, 并且避免了所有角度的计算。 
    如下是一个更直观的算法:
    1. 计算多边形 y 方向上的端点。 我们称之为 ymin 和 ymax 。
    2. 通过 ymin 和 ymax 构造两条水平切线。 由于他们已经是一对对踵点, 计算他们之间的距离并维护为一个当前最大值。
    3. 同时旋转两条线直到其中一条与多边形的一条边重合。
    4. 一个新的对踵点对此时产生。 计算新的距离, 并和当前最大值比较, 大于当前最大值则更新。
    5. 重复步骤3和步骤4的过程直到再次产生对踵点对 (ymin,ymax) 。
    6. 输出确定最大直径的对踵点对。
    至此, 上述的过程(伪代码中的)显得十分有用, 我们可以从对踵点对中得到其他的信息, 如多边形的宽度 。
    程序:
    #include"string.h"
    #include"stdio.h"
    #include"math.h"
    #include"stdlib.h"
    #define M 50001
    #define inf 999999999
    #define eps 1e-10
    typedef struct node
    {
        double x,y,cos,dis;
    }E;
    E p[M],q[M];
    double max(double a,double b)
    {
        return a>b?a:b;
    }
    int cmp(const void *a,const void *b)
    {
        if(fabs((*(struct node*)a).cos-(*(struct node*)b).cos)<eps)
            return (*(struct node*)a).dis>(*(struct node*)b).dis?1:-1;
        else
            return (*(struct node*)b).cos>(*(struct node*)a).cos?1:-1;
    }
    double angle(node p1,node p2)
    {
        double x1=p2.x-p1.x;
        double y1=p2.y-p1.y;
        double x2=1;
        double y2=0;
        return (x1*x2+y1*y2)/sqrt((x1*x1+y1*y1)*(x2*x2+y2*y2));
    }
    double pow(double x)
    {
        return x*x;
    }
    double Len(node p1,node p2)
    {
        return pow(p2.x-p1.x)+pow(p2.y-p1.y);
    }
    double cross(node p0,node p1,node p2)
    {
        double x1=p1.x-p0.x;
        double y1=p1.y-p0.y;
        double x2=p2.x-p0.x;
        double y2=p2.y-p0.y;
        return x1*y2-x2*y1;
    }
    int main()
    {
        int n,i,j;
        while(scanf("%d",&n)!=-1)
        {
            int tep;
            E start;
            start.x=start.y=inf;
            for(i=0;i<n;i++)
            {
                scanf("%lf%lf",&p[i].x,&p[i].y);
                if(p[i].y<start.y)
                {
                    start=p[i];
                    tep=i;
                }
                else if(fabs(p[i].y-start.y)<eps)
                {
                    if(p[i].x<start.x)
                    {
                        start=p[i];
                        tep=i;
                    }
                }
            }
            p[tep].dis=0;
            p[tep].cos=10;
            for(i=0;i<n;i++)
            {
                if(i!=tep)
                {
                    p[i].cos=angle(start,p[i]);
                    p[i].dis=Len(start,p[i]);
                }
            }
            qsort(p,n,sizeof(p[0]),cmp);
            q[0]=p[n-1];
            q[1]=p[0];
            q[2]=p[1];
            int cnt=2;
            for(i=2;i<n;i++)
            {
                while(cross(q[cnt-1],q[cnt],p[i])<0)
                {
                    cnt--;
                }
                q[++cnt]=p[i];
            }//求凸包
            j=1;
            double max_dis=0;
            for(i=0;i<cnt;i++)
            {
                while(cross(q[i],q[(i+1)%cnt],q[(j+1)%cnt])>cross(q[i],q[(i+1)%cnt],q[j%cnt]))
                    j=(j+1)%cnt;
                max_dis=max(max_dis,Len(q[j],q[i]));
                max_dis=max(max_dis,Len(q[j],q[(i+1)%cnt]));
            }//旋转卡壳法求两点间最长距离,最长距离的点一定在凸包上
            printf("%.0lf
    ",max_dis);
        }
    }
    


  • 相关阅读:
    CentOS 6.6 下源码编译安装MySQL 5.7.5
    CentOS 6.6下安装配置Tomcat环境
    Redhat6.7 切换Centos yum源
    css盒模型
    mysql 查询表占用空间大小
    ligerform 控件元素设置为只读
    FtpClient中文文件名下载失败问题
    java Runtime.exec() 执行问题
    java log4j动态生成log文件
    java udp地址匹配
  • 原文地址:https://www.cnblogs.com/mypsq/p/4348245.html
Copyright © 2020-2023  润新知