• 几何:极角排序详解


    关于极角排序:

      在平面内取一个定点O,叫极点,引一条射线Ox,叫做极轴,再选定一个长度单位和角度的正方向(通常取逆时针方向)。

      对于平面内任何一点M,用ρ表示线段OM的长度(有时也用r表示),θ表示从Ox到OM的角度,ρ叫做点M的极径,θ叫做点M的极角,有序数对 (ρ,θ)就叫点M的极坐标。

      那么给定平面上的一些点,把它们按照一个选定的中心点排成顺(逆)时针。

    极角排序常用的四种方法:

      在说四种方法之前,给出一会用到的函数和存储点的结构体

    struct point//存储点
    {
        double x,y;
    };
    
    double cross(double x1,double y1,double x2,double y2) //计算叉积
    {
        return (x1*y2-x2*y1);
    }
    
    double compare(point a,point b,point c)//计算极角
    {
        return cross((b.x-a.x),(b.y-a.y),(c.x-a.x),(c.y-a.y));
    }

    方法1:利用atan2()函数按极角从小到大排序。

        关于atan2()函数:在C语言的math.h或C++中的cmath中有两个求反正切的函数atan(double x)与atan2(double y,double x)  他们返回的值是弧度要转化为角度再自己处理下。

    前者接受的是一个正切值(直线的斜率)得到夹角,但是由于正切的规律性本可以有两个角度的但它却只返回一个,因为atan的值域是从-90~90 也就是它只处理一四象限,所以一般不用它。

    第二个atan2(double y,double x) 其中y代表已知点的Y坐标,同理x ,返回值是此点与远点连线与x轴正方向的夹角,这样它就可以处理四个象限的任意情况了,它的值域相应的也就是-180~180了

    bool cmp1(point a,point b)
    {
        if(atan2(a.y,a.x)!=atan2(b.y,b.x))
            return atan2(a.y,a.x)<atan2(b.y,b.x);
        else return a.x<b.x;
    }

    方法2:利用叉积按极角从小到大排序。

        关于叉积:叉积=0是指两向量平行(重合);叉积>0,则向量a在向量b的顺时针方向(粗略的理解为在a在b的下方);叉积<0,则向量a在向量b的逆时针方向(粗略的理解为在a在b的上方)

    bool cmp2(point a,point b) 
    {
        point c;//原点
        c.x = 0;
        c.y = 0;
        if(compare(c,a,b)==0)//计算叉积,函数在上面有介绍,如果叉积相等,按照X从小到大排序
            return a.x<b.x;
        else return compare(c,a,b)>0;
    }

    方法3:先按象限从小到大排序 再按极角从小到大排序

    int Quadrant(point a)  //象限排序,注意包含四个坐标轴
    {
        if(a.x>0&&a.y>=0)  return 1;
        if(a.x<=0&&a.y>0)  return 2;
        if(a.x<0&&a.y<=0)  return 3;
        if(a.x>=0&&a.y<0)  return 4;
    }
    
    
    bool cmp3(point a,point b)  //先按象限从小到大排序 再按极角从小到大排序
    {
        if(Quadrant(a)==Quadrant(b))//返回值就是象限
            return cmp1(a,b);
        else Quadrant(a)<Quadrant(b);
    }

    关于三种方法的比较:

      第三种方法按象限从小到大排序 再按极角从小到大排序是在有特殊需求的时候才会用到,这里不做比较。

      关于第一种方法,利用atan2排序,他和利用叉积排序的主要区别在精度和时间上。

      具体对比:时间:相较于计算叉积,利用atan2时间快,这个时间会快一点(记得做过一个题用atan2排序过了,用叉积的T了)

             精度: atan2精度不如叉积高,做过一个题用anat2因为精度问题WA了。

      所以两种方法根据情况选择一种合适的使用。

  • 相关阅读:
    [IOI1998] Pictures
    【C++】位操作(3)-获取某位的值
    PAT A 1013. Battle Over Cities (25)【并查集】
    hihoCoder 1391 Countries【预处理+排序+优先队列】2016北京网络赛
    PAT A 1014. Waiting in Line (30)【队列模拟】
    codeforces Round#379 div.2
    PAT A 1004. Counting Leaves (30)【vector+dfs】
    POJ 1163:The Triangle
    LeetCode39/40/22/77/17/401/78/51/46/47/79 11道回溯题(Backtracking)
    BZOJ 3680 吊打XXX
  • 原文地址:https://www.cnblogs.com/aiguona/p/7248311.html
Copyright © 2020-2023  润新知