水平序 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 = ;
const double eps = 1e-; struct POINT{
int x;
int y;
POINT() : x(), y() {};
POINT(double _x_, double _y_) : x(_x_), y(_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 =;
sort(pnt, pnt + n);
if (n == )
return ;
res[] = pnt[];
if (n == )
return ;
res[] = pnt[];
if (n == )
return ;
res[] = pnt[];
for (i =; i < n; i++){
while (top && Cross(pnt[i], res[top], res[top -]) >= )
top--;
res[++top] = pnt[i];
}
len = top;
res[++top] = pnt[n -];
for (i = n -; i >=; i--){
while (top != len && Cross(pnt[i], res[top], res[top -]) >= )
top--;
res[++top] = pnt[i];
}
return top;
} int rotating_calipers(POINT *ch, int n){
int q =, ans =;
ch[n] = ch[];
for (int i = ; i < n; ++i){
while (Cross(ch[i + ], ch[q + ], ch[i]) > Cross(ch[i + ], ch[q], ch[i]))
q = (q +) % n;
ans = max(ans, max(SquareDis(ch[i], ch[q]), SquareDis(ch[i + ], ch[q + ])));
}
return ans;
} int main(){
POINT pnt[MAXN], res[MAXN];
int n;
while(EOF != scanf("%d",&n)){
for (int i = ; 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 ;
}

POJ 2187 旋转卡壳 + 水平序 Graham 扫描算法 + 运算符重载的更多相关文章

  1. Poj 2187 旋转卡壳

    Poj 2187 旋转卡壳求解 传送门 旋转卡壳,是利用凸包性质来求解凸包最长点对的线性算法,我们逐渐改变每一次方向,然后枚举出这个方向上的踵点对(最远点对),类似于用游标卡尺卡着凸包旋转一周,答案就 ...

  2. 二维凸包 Graham扫描算法

    题目链接: http://poj.org/problem?id=1113 求下列点的凸包 求得凸包如下: Graham扫描算法: 找出最左下的点,设为一号点,将其它点对一号点连线,按照与x轴的夹角大小 ...

  3. poj 2079(旋转卡壳求解凸包内最大三角形面积)

    Triangle Time Limit: 3000MS   Memory Limit: 30000K Total Submissions: 9060   Accepted: 2698 Descript ...

  4. [poj1113][Wall] (水平序+graham算法 求凸包)

    Description Once upon a time there was a greedy King who ordered his chief Architect to build a wall ...

  5. poj 3608(旋转卡壳求解两凸包之间的最短距离)

    Bridge Across Islands Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 9768   Accepted: ...

  6. Bridge Across Islands POJ - 3608 旋转卡壳求凸包最近距离

    \(\color{#0066ff}{题目描述}\) 几千年前,有一个小王国位于太平洋的中部.王国的领土由两个分离的岛屿组成.由于洋流的冲击,两个岛屿的形状都变成了凸多边形.王国的国王想建立一座桥来连接 ...

  7. POJ 3608 旋转卡壳

    思路: 旋转卡壳应用 注意点&边  边&边  点&点 三种情况 //By SiriusRen #include <cmath> #include <cstdi ...

  8. poj 3608 旋转卡壳求不相交凸包最近距离;

    题目链接:http://poj.org/problem?id=3608 #include<cstdio> #include<cstring> #include<cmath ...

  9. POJ C++程序设计 编程题#3 编程作业—运算符重载

    编程题 #3 来源: POJ (Coursera声明:在POJ上完成的习题将不会计入Coursera的最后成绩.) 注意: 总时间限制: 1000ms 内存限制: 65536kB 描述 写一个二维数组 ...

随机推荐

  1. android studio 快捷笔记

    setting->editor->打勾 ctrl+Q ctrl+tab alt+回车 ctrl+shift+回车

  2. Spring Boot 属性配置和使用

    Spring Boot 属性配置和使用 Spring Boot 允许通过外部配置让你在不同的环境使用同一应用程序的代码,简单说就是可以通过配置文件来注入属性或者修改默认的配置. Spring Boot ...

  3. Windows Azure 网站自愈

    编辑人员注释:本文章由 Windows Azure 网站团队的项目经理Apurva Joshi 撰写. 您有多少次在半夜被叫醒去解决一个仅需重新启动网站即可解决的问题?要是可以自动检测一些状况并自动恢 ...

  4. C++模板:qsort

    void qsort(int l,int r){ int i,j,t,mid; mid=b[(l+r)>>1]; i=l; j=r; do{ while (b[i]<mid) i++ ...

  5. rpc的学习

    rpc(Remote process call 即远程过程调用)是一种请求-相应的协议, 主要使用于C/S架构中,使得分布式系统成为可能.由客户端发起请求,服务端调用各种参数处理请求,当服务器在处理请 ...

  6. STL algorithm算法mismatch(37)

    mismatch原型: std::mismatch equality (1) template <class InputIterator1, class InputIterator2> p ...

  7. HDU 1711 Number Sequence KMP

    题目地址: http://acm.hdu.edu.cn/showproblem.php?pid=1711 AC代码: #include <iostream> #include <cs ...

  8. aliyun硬盘挂载

    实在难以忍受公司服务器的网络问题,停用了半年的aliyun服务器今天终于决定启用了. 购买的时候是40G的硬盘空间,首先查了一硬盘情况结果发现有一个分区居然没有挂载.  第一步是创建一个分区 输入命令 ...

  9. shell:监控进程运行状态并自动重启进程

    #!/bin/sh MAXRSTCOUNT=; PROCTOGO=/mnt/hgfs/code/test/show #count is the counter of test started time ...

  10. shell学习之常用命令总结

    1.find命令 主要用途:主要用来做文件查找. 使用方法:查找文件的方式可以基于:文件名,文件时间属性,文件的所有者和组,文件权限属性,文件类型属性,文件大小,另外可以指定 查找目录的深度,排除指定 ...