旋转卡壳法求凸包的直径

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\n",max_dis);
    }
}


转载于:https://www.cnblogs.com/mypsq/p/4348245.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值