凸包 Gramham 扫描法

今天突然看见凸包题,然后翻看自己以前学的时候写的博客,竟然发现那个学习的链接没了,就去看了算法导论,然后对着模板,把这个算法看了一遍,东西还是要多看几遍的,每次看都有不同的感受,总会有那么一次,你会发出一句感慨:呃,原来是这样啊!现在把模板整理一下吧

先说一下求解步骤:

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

posted @ 2012-08-20 21:23  AC_Girl  阅读(674)  评论(0编辑  收藏  举报