先找到纵坐标最小的点,如果有多个找横坐标最小,设该点为p0,以p0为原点,对所有点进行极角排序,排序规则:链接pip0与横坐标正方向的夹角小的编号小,如果夹角相同,距离p0近的编号小,排完序之后,p0p1pn这三个点一点是凸包上的点(上图的p0p1p8),从编号为2的点依次遍历所有的点,每次取栈顶的两个点连城一条直线(方向由栈顶的第二个点指向栈顶)与当前的点pi比较,如果pi在直线的左侧pi直接入栈,如果pi在直线的右侧,弹出栈顶的一个点,继续取栈内两个点与pi比较,直到pi在直线的左侧将pi入栈。
最后栈内剩下的所有点就是凸包上的点。
double multi(node p1, node p2, node p3)
{
return p1.x*p2.y+p3.x*p1.y+p2.x*p3.y-p3.x*p2.y-p2.x*p1.y-p1.x*p3.y;
}
double distence(node a, node b)
{
return sqrt((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y));
}
bool cmp(node a, node b)
{
if(equal(multi(minp,a,b)))
return distence(minp,a) - distence(minp,b) < 0;
return multi(minp,a,b) > 0;
}
void Graham(int n, int &top)
{
sort(p,p+n,cmp);
s[0] = p[0];
s[1] = p[1];
top = 2;
for(int i = 2;i < n;i++)
{
while(multi(s[top-2],s[top-1],p[i]) < 0)
top--;
s[top++] = p[i];
}
}