首页 > 代码库 > POJ 2187 旋转卡壳 + 水平序 Graham 扫描算法
POJ 2187 旋转卡壳 + 水平序 Graham 扫描算法
水平序 Graham 扫描算法:
计算二维凸包的时候可以用到,Graham 扫描算法有水平序和极角序两种。
极角序算法能一次确定整个凸包,
但是计算极角需要用到三角函数,速度较慢,精度较差,特殊情况较多。
水平序算法需要扫描两次,但排序简单,讨论简单,不易出错。
【算法流程】
1.对顶点按x为第一关键字,y为第二关键字进行排序。
2.准备一个空栈,并将前两个点压入栈。
3.对于每一个顶点A,只要栈顶中还至少两个顶点,记栈顶为T,栈中第二个为U。
若UT(向量) * TA(向量) <= 0, 则将T弹出。重复此过程。
4.直到上一步不再弹出顶点,将A压入栈。扫描完一遍之后得到凸包的下凸壳。
5.将点集倒过来再进行一次,得到凸包的上凸壳,组合起来即可。
【算法的时间复杂度】
算法的瓶颈在排序,所以时间复杂度是 O(N log N)。 若坐标均为整数,可以用基数排序将复杂度优化到 O(N)。
贴上代码了~:
//#pragma comment(linker, "/STACK:16777216") //for c++ Compiler#include <stdio.h>#include <iostream>#include <cstring>#include <cmath>#include <stack>#include <queue>#include <vector>#include <algorithm>#define ll long long#define Max(a,b) (((a) > (b)) ? (a) : (b))#define Min(a,b) (((a) < (b)) ? (a) : (b))#define Abs(x) (((x) > 0) ? (x) : (-(x)))using namespace std;const int INF = 0x3f3f3f3f;const int MAXN = 50001;const double eps = 1e-8;struct POINT{ int x; int y; POINT() : x(0), y(0) {}; POINT(double _x_, double _y_) : x(_x_), y(_y_) {};};bool Mult(const POINT & sp, const POINT & ep, const POINT & op){ return (sp.x - op.x) * (ep. y - op.y) >= (ep.x - op.x) * (sp.y - op.y);}bool operator < (const POINT & l, const POINT & r){ return l.y < r. y || (l.y == r.y && l.x < r.x);}int Cross(const POINT & a, const POINT & b, const POINT & o){ return (a.x - o.x) * (b.y - o.y) - (b.x - o.x) * (a.y - o.y);}int SquareDis(POINT a, POINT b){ return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y);}int Graham(POINT *pnt, POINT *res, int n){ int i, len, top =1; sort(pnt, pnt + n); if (n == 0) return 0; res[0] = pnt[0]; if (n == 1) return 1; res[1] = pnt[1]; if (n == 2) return 2; res[2] = pnt[2]; for (i =2; i < n; i++){ while (top && Mult(pnt[i], res[top], res[top -1])) top--; res[++top] = pnt[i]; } len = top; res[++top] = pnt[n -2]; for (i = n -3; i >=0; i--){ while (top != len && Mult(pnt[i], res[top], res[top -1])) top--; res[++top] = pnt[i]; } return top;}int rotating_calipers(POINT *ch, int n){ int q =1, ans =0; ch[n] = ch[0]; for (int i = 0; i < n; ++i){ while (Cross(ch[i + 1], ch[q + 1], ch[i]) > Cross(ch[i + 1], ch[q], ch[i])) q = (q +1) % n; ans = max(ans, max(SquareDis(ch[i], ch[q]), SquareDis(ch[i + 1], ch[q + 1]))); } return ans;}int main(){ POINT pnt[MAXN], res[MAXN]; int n; while(EOF != scanf("%d",&n)){ for (int i = 0; i < n; i++) scanf("%d%d", &pnt[i].x, &pnt[i].y); int count = Graham(pnt, res, n); int ans = rotating_calipers(res, count); printf("%d\n", ans); } return 0;}
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。