转载摘自大神博客:
https://thewalker88.com/?p=84
求组成凸包的点坐标,周长面积等问题
针对这个问题:Melkman复杂度n,且可以在线处理,而Graham复杂度nlogn(因为必须先排序)
平面上有一个简单多边形,沿着多边形的边,按照逆时针的顺序给出多边形的顶点的坐标,要求你求出此多边形的凸包。
如果是一般散点集问题的话,那它跟Graham复杂度相同,均需要先排个序nlogn
melkman算法想象成渔网网鱼就成,左右边同时包揽
struct Vector { double x, y; }; struct Point { double x, y; } p[N],dq[N]; bool cmp(Point a, Point b) { if (a.y == b.y) return a.x < b.x; return a.y < b.y; } double Cross(Vector A, Vector B) { return A.x * B.y - A.y * B.x; }//叉乘,右手螺旋,左上正右下负 double side(Point a, Point b, Point p)//判断p在a->b直线那一侧 { Vector A = (Vector){b.x - a.x, b.y - a.y}; Vector B = (Vector){p.x - a.x, p.y - a.y}; return Cross(A, B); } void Melkman(int n, int &head, int &tail) { sort(p + 1, p + 1 + n, cmp);//如果是处理一般点集问题,这里排序保证了这只“渔网”从西南角往东北角突击 dq[head = n] = p[2];//这里直接丢1,2进来,3并不需要如网上说的手动调 dq[tail = n + 1] = p[1]; dq[++tail] = p[2]; For(i, 3, n) { // if (side(dq[head + 1], dq[head], p[i])<0 && side(dq[tail - 1], dq[tail], p[i])>0)//如果是处理简单多边形的题要加这句话 // continue; while (tail - head >= 2 && side(dq[head + 1], dq[head], p[i]) >= 0)//head+1->head从左路包揽敌人,如果有更左侧的鱼,那就调整角度向左扩张渔网 ++head; dq[--head] = p[i]; while (tail - head >= 2 && side(dq[tail - 1], dq[tail], p[i]) <= 0 )//tail-1->tail从右路包揽敌人 --tail; dq[++tail] = p[i]; } } For(i,head,tail-1)//因为head和tail存的值一定相同,输出点坐标输出一边就行 cout<<dq[i].x<<" "<<dq[i].y<<endl;