我正在阅读格雷厄姆扫描算法以从CLRS中找到凸包。 CLRS for Convex hull中给出的算法是::
我无法理解这一行(算法的第2步):
如果两个或多个点相对于p0具有相同的极角,则除了最远的点之外的所有点都是p0和最远点的凸组合,因此我们完全不考虑它们。
也可以说,我已经建立了一个结构
struct points
{
int x, y;
} P[10000];
sort(P+1, P+N, comparator)
?答案 0 :(得分:3)
这是什么意思,如果不止一个点与Po有相同的极角,我该怎么办?
假设P 0 是(0,0)
,P 1 是(1,1)
而P 2 是{{1 }}。现在P 1 和P 2 具有相对于P 0 的相同角度,在这种情况下你丢弃P 1 。如果P 0 和P 2 之间的角度相同,则丢弃 all ,除了P 2 (当然,P 0 。
我应该如何使用C ++ STL(算法中的排序函数)库实现排序步骤?特别是我的意思是排序(P + 1,P + N,比较器)。我该如何定义比较器功能?
不熟悉C ++(STL),但检查它是否具有可以使用的(2,2)
功能。另请参阅:Find angle between two points, respective to horizontal axis?和How to calculate the angle between a line and the horizontal axis?
答案 1 :(得分:3)
这是我在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;
}
要么你可以使用比较器功能,要么u可以使运算符过载&lt;就像我在这里做的那样。这将类似地工作,但现在你不必将任何比较器函数作为sort()函数
中的第三个参数传递我希望这会有所帮助
答案 2 :(得分:2)
(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<Point> 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);
}