我的第一道凸包题,终于弄懂了Graham算法,对我来说弄懂一个算法是一个痛苦的过程,我痛苦了我好几天……
Grahma算法模板:
1、 寻找一个基准点,这个点通常是最左边的最下面那个点(其实只要这个点一定会在凸包边界上就行),然后将之个点置于第一个位置。
2、 将所有点按相对于基准点的极角排序。
3、 因为排序之后前两个点一定会在凸包上,假设第三个点也在凸包上,因此我们可以从第四个点开始依次扫描每个点。对于每个当前点他在当前时刻是极角最大的点,所以在当前时刻它必定在凸包上,那么此时就可能改变了它前一个点是不是在凸包上。怎么判断呢?我们可以咱当前点到推三个点,假设是p1,p2,p3,判断这三个点所形成的角是不是大于180度,小于180度继续扫描下一个点,若大于180度说明第二个点一定在凸包内部,然后我们暂时停止扫描下一个点,将p1,p2各自后退一个点继续判断p1,p2,p3所组成的角是不是大于180度,(这也就是所谓的“退化”问题,看了《算法导论》后才知道这儿需要有个循环)若仍然大于180度循环这种操作直到三个点组成的角小于等于180度,最后继续扫描下一个点,直到结束。在这个过程中我们可以用栈来保存凸包边上的点。
该题需要最后算出各边长的和再加上圆的周长。
#include<iostream> #include<cmath> using namespace std; #define MAX_INT 123456789 struct point { int x,y; }; point vertex[1001],stack[1000]; int angle(point p1,point p2,point p0)//判断极角大小 { return (p1.y-p0.y)*(p2.x-p0.x)-(p2.y-p0.y)*(p1.x-p0.x); } int dist(point p1,point p2) { return (p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y); } int cmp(const void* pp,const void* qq)//排序判断条件 { point p1,p2; p1=*(point*) pp; p2=*(point*) qq; if(angle(p1,p2,vertex[0])>0) return 1; else if(angle(p1,p2,vertex[0])==0 && dist(p1,vertex[0])>dist(p2,vertex[0])) return 1; return -1; } int judge(point p1,point p2,point p3)//判断三点组成的角度 { return (p3.y-p2.y)*(p2.x-p1.x)-(p2.y-p1.y)*(p3.x-p2.x); } double Graham(int n,int m) { int sum_max=0,i=0; point p1,p2; double sum=0; p1=vertex[1],p2=vertex[2]; stack[0]=vertex[0]; stack[1]=vertex[1]; stack[2]=vertex[2]; sum_max=2; for(i=3;i<n;i++) { while(1)//解决退化问题 { if(judge(p1,p2,vertex[i])>=0) { p1=p2,p2=vertex[i]; stack[++sum_max]=vertex[i]; break; } else { --sum_max; p2=stack[sum_max]; p1=stack[sum_max-1]; } } } for(i=0;i<sum_max;i++) sum+=sqrt((double)dist(stack[i],stack[i+1])); sum+=sqrt((double)dist(stack[sum_max],vertex[0]))+3.1415926*2*m; return sum; } int main() { int i,m,n,min; point minPoint; while(scanf("%d%d",&n,&m)!=EOF) { memset(vertex,0,sizeof(vertex)); minPoint.x=minPoint.y=MAX_INT; for(min=i=0;i<n;i++) { scanf("%d%d",&vertex[i].x,&vertex[i].y); if(minPoint.x>vertex[i].x) { minPoint=vertex[i]; min=i; } else if(minPoint.x==vertex[i].x && minPoint.y>vertex[i].y) { minPoint=vertex[i]; min=i; } } vertex[min]=vertex[0]; vertex[0]=minPoint; qsort(vertex+1,n-1,sizeof(vertex[0]),cmp); printf("%.lf\n",Graham(n,m)); } return 0; }