今天突然看见凸包题,然后翻看自己以前学的时候写的博客,竟然发现那个学习的链接没了,就去看了算法导论,然后对着模板,把这个算法看了一遍,东西还是要多看几遍的,每次看都有不同的感受,总会有那么一次,你会发出一句感慨:呃,原来是这样啊!现在把模板整理一下吧
先说一下求解步骤:
1.首先在输入的点集中找出一个对照点,放入到 p[0]中,这个对照点就是 在点集的最下,最左的那个点
2.对 1 ~ n - 1的点按相对于 对照点的极角从小到大排序,如果极角相同那么就按距离对照点的远近从小到大排序
3.把输入的点集的前两个点放入到栈中,然后依次扫描剩余的点,把不是凸包顶点的点从栈中剔除,沿逆时针方向通过凸包时,在每个顶点处应该左转,因此,如果发现在顶点处没有左转,就可以从栈里弹出了,把向左转的点加入到栈中
最后栈里面保存的就是凸包的顶点
View Code
1 struct node 2 { 3 int x,y; 4 }point[N],stack[N]; 5 int top,n; 6 int pows(int x) 7 { 8 return x * x; 9 } 10 double dis(node a,node b) 11 { 12 return sqrt((double)(pows(a.x - b.x) + pows(a.y - b.y))); // 计算距离 13 } 14 double mul(node a,node b,node c) 15 { 16 return (c.x - a.x) * (b.y - a.y) - (c.y - a.y) * (b.x - a.x); // 叉积判断方向和计算极角 17 } 18 int cmp(const void *a,const void *b) 19 { 20 node *c = (node *)a; 21 node *d = (node *)b; 22 int m = mul(point[0],*c,*d); 23 if(m == 0) return dis(*c,point[0]) - dis(*d,point[0]); // 如果极角为零,那么按距离从小到大排序 24 else return -m; 25 } 26 void gram() 27 { 28 int i; 29 int temp = 0; 30 for(i = 0; i < n; i++) 31 { 32 if(point[i].y < point[temp].y || (point[i].y == point[temp].y && point[i].x < point[temp].x)) // 寻找对照点 33 temp = i; 34 } 35 swap(point[0],point[temp]); // 保存到 point[0] 36 qsort(point + 1,n - 1,sizeof(node),cmp); // 排序 37 top = 1; 38 stack[0] = point[0]; 39 stack[1] = point[1]; 40 for(i = 2; i < n; i++) 41 { 42 while(top >= 1 && mul(stack[top - 1],stack[top],point[i]) <= 0) top--; // 如果在顶点处不是左转那么说明不是凸包的顶点,就剔除 43 stack[++top] = point[i]; // 左转的点保存到栈里 44 } 45 }
附加两道题目:http://www.cnblogs.com/fxh19911107/archive/2012/05/05/2485214.html