【问题标题】:Convex Hull Sorting Step凸包分拣步骤
【发布时间】:2012-07-13 02:04:58
【问题描述】:

我正在阅读格雷厄姆扫描算法以从 CLRS 中找到凸包。 CLRS 中针对 Convex hull 给出的算法是 ::

我无法理解这一行(算法的第 2 步):

如果两个或多个点相对于 p0 具有相同的极角,那么除了最远的点之外,其他所有点都是 p0 和最远点的凸组合,因此我们完全不考虑它们。

  1. 这是什么意思?如果多个点相对于 Po 的极角相同怎么办?

还可以说,我已经做了一个结构

struct points
{
    int x, y;
} P[10000];
  1. 我应该如何使用 C++ STL 库实现排序步骤?我的意思是,我应该如何定义sort(P+1, P+N, comparator)中的比较器函数?

【问题讨论】:

标签: algorithm computational-geometry convex-hull


【解决方案1】:

这是什么意思,如果多个点相对于Po有相同的极角怎么办?

假设 P0(0,0),P1(1,1),P2(2,2)。现在 P1 和 P2 相对于 P0 具有相同的角度,在这种情况下你丢弃 P1 .如果在 P0 和 P2 之间还有更多相同角度的点,则丢弃除 P2 之外的 all (当然还有 P0)。

我应该如何使用 C++ STL(算法中的排序函数)库实现排序步骤?特别是我的意思是排序(P+1,P+N,比较器)。应该如何定义比较函数?

不太熟悉 C++ (STL),但请检查它是否具有您可以使用的 atan2 函数。另请参阅:Find angle between two points, respective to horizontal axis?How to calculate the angle between a line and the horizontal axis?

【讨论】:

  • 谢谢!!!所以你的意思是,在平局的情况下,即当有n个点相对于Po的极角相同时,我应该只考虑到Po的欧几里得距离最大的点。
【解决方案2】:

这是我在 C++ 中对凸包的 gharam 扫描算法的实现

struct vert
{
    int x,y;
    float rad;
    int idx;
};    
bool operator<(const vert &a,const vert &b)//this is the function u are looking for
{
    if(a.rad<b.rad)
        return true;
    if(a.rad==b.rad)
    {
        if(a.y>b.y)
            return true;
        else if(a.y==b.y&&a.x>b.x)
            return true;
        else
            return false;
    }
    return false;
}    
vert operator-(vert x,vert y)
{
    vert tmp;
    tmp.x=x.x-y.x;
    tmp.y=x.y-y.y;
    return tmp;
}
double dist(vert a,vert b)
{
    vert ab=b-a;
    return sqrt(ab.x*ab.x+ab.y*ab.y);
}
int cross(vert a,vert b,vert c)
{
    vert ab,bc;
    ab=b-a;
    bc=c-b;
    return ab.x*bc.y-ab.y*bc.x;
}
int main()
{
    int t,i,j,k,n;
    //("example.txt","r",stdin);
    scanf("%d",&t);
    vert a[100009],point[100009];
    int kx,ky;
    while(t--)
    {
        scanf("%d",&n);
        for(i=0;i<n;i++)
        {
            scanf("%d%d",&a[i].x,&a[i].y);
            a[i].idx=i+1;
        }
        vert d;
        d=a[0];
        for(i=1;i<n;i++)
        {
            if(a[i].y<d.y)
                d=a[i];
            else if(a[i].y==d.y&&a[i].x<d.x)
                d=a[i];
        }
        vector<vert> v;
        for(i=0;i<n;i++)
        {
            kx=a[i].x-d.x;
            ky=a[i].y-d.y;
            if(kx==0&&ky==0)
                continue;
            a[i].rad=atan2(kx,ky)*-1.00;
            v.push_back(a[i]);
        }
        sort(v.begin(),v.end());
        float rad=-10000;
        j=0;
        for(i=0;i<v.size();i++)
        {
            if(v[i].rad!=rad)
            {
                a[j++]=v[i];
                rad=v[i].rad;
            }
        }
        k=0;
        point[k++]=d;
        for(i=0;i<j;i++)
        {
            if(k<=1)
                point[k++]=a[i];
            if(cross(point[k-2],point[k-1],a[i])>0)
            {
                point[k++]=a[i];
            }
            else
            {
                do
                {
                    k--;
                    if(cross(point[k-2],point[k-1],a[i])>0)
                        break;
                }while(k>1);
                point[k++]=a[i];
            }
        }
        double dis=0;
        for(i=1;i<k;i++)
            dis+=dist(point[i],point[i-1]);
        dis+=dist(point[0],point[k-1]);
        printf("%0.2f\n",dis);
        for(i=0;i<k;i++)
            printf("%d ",point[i].idx);
        cout<<endl<<endl;;
    }
    return 0;
}

你可以使用比较器函数或者你可以重载操作符

希望对你有帮助

【讨论】:

    【解决方案3】:

    (B)我应该如何使用 C++ STL(算法中的排序函数)库实现排序步骤?特别是我的意思是排序(P+1,P+N,比较器)。应该如何定义比较函数?

    我建议你避免凌乱的浮点运算。正如同一本书的练习 33.1-3 所指出的,您可以使用叉积简单地按极角排序。操作方法如下:

    struct Point {int x,y;}
    
    int operator^(Point p1, Point p2) {return p1.x*p2.y - p1.y*p2.x;}
    
    Point p0; //set this separately
    
    bool operator<(Point p1, Point p2) 
    {
        p1=p1-p0; p2=p2-p0; 
        if(p1.y==0&&p1.x>0) return true; //angle of p1 is 0, thus p2>p1
        if(p2.y==0&&p2.x>0) return false; //angle of p2 is 0 , thus p1>p2
        if(p1.y>0&&p2.y<0) return true; //p1 is between 0 and 180, p2 between 180 and 360
        if(p1.y<0&&p2.y>0) return false;
        return (p1^p2)>0; //return true if p1 is clockwise from p2
    }
    

    (A)这是什么意思,如果多个点相对于Po有相同的极角怎么办?

    如果 p0、pi 和 pj 共线,只有离 p0 最远的那个可能是凸包的一部分。因此,我们应该删除其他点。我们可以在 C++ 中做到这一点。首先定义点积,

    int operator*(Point p1, Point p2) {return p1.x*p2.x + p1.y*p2.y;}
    

    并将这一行添加到比较器中:

    if((p1^p2)==0&&p1*p2>0) return p1*p1<p2*p2;
    

    现在在相同角度的情况下,点将按距 p0 的距离排序。现在我们可以使用 STL 中的unique 函数来根据需要从vector&lt;Point&gt; P 中删除点:

    sort(P.begin(),P.end());
    P.erase(unique(P.begin(),P.end(),eq),P.end());
    

    这里,如果点的角度相同,eq 函数将返回 true。

    bool eq(Point p1, Point p2) 
    {
        p1=p1-p0; p2=p2-p0;
        return ((p1^p2)==0&&p1*p2>0); 
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-04-05
      • 2018-12-29
      • 2013-02-27
      • 2011-05-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-07-20
      相关资源
      最近更新 更多