Graham Scan算法
预备知识:凸集:集合S中任意两点的连线都在集合S中,如果简单的理解,可以理解为凸边形
凸包:对于给定集合X,所有包含X的凸集的交集,简单的理解,就是包含X的最小凸集,或者就是最外圈的点连起来
极角排序
用叉乘判断方向:向量a叉乘向量b的值就是|a| |b| sinθ,θ是向量a逆时针旋转到向量b的角度(右手定则),所以叉积是正的就是逆时针旋转过去,等于0就是共线,小于零就是逆时针旋转过去的
Graham Scan算法是一个用来求凸包的算法
第一步:把点按逆时针顺序排好
具体做法:找到左下角的点(横坐标和纵坐标都是最小的),以这个点为极点,想象有一个平行于x轴的并且和x轴正方向同向的极轴,然后进行极角排序
第二步:找凸包
具体做法:开一个栈,top=元素个数,从第0个点遍历到第n个再到第0个
对于第i个点,构造向量a(top-2->top-1),向量b(top-2->i),计算向量a 叉乘 向量b,
如果不足两个点,i入栈
如果=0,说明共线,可以i入栈
如果>0,说明是逆时针的,可以i入栈
如果是<0说明已经凹进去了,第top-1点不符合凸包的定义,top-1出栈,--top,重复执行,直到成功入栈
结合图理解就是如果连2,3的话就已经凹进去了(左上角的)
下面看一个维基的动态版本
代码
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
class point {
public:double x, y;point(const double &x = 0, const double &y = 0) :x(x), y(y) {}
};
int n;
//p是点集,convex是栈
point p[1005], convex[1005];
//叉乘
double cross(const point &a, const point &b, const point &c, const point &d) {return (b.x - a.x)*(d.y - c.y) - (b.y - a.y)*(d.x - c.x);
}
//极角排序,角度相同按x升序
bool cmp(const point &a, const point &b) {double temp = cross(p[0], a, p[0], b);if (!temp)return a.x < b.x;return temp > 0;
}
//距离
double getDistance(const point &a, const point &b) {return sqrt(1.0*(a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y - b.y));
}
//graham scan算法,返回凸包顶点个数
int graham() {int top = 0, i = 0;while (i <= n) {//不足两个直接入栈,否则叉积判断方向,直到成功入栈while (top >= 2 && cross(convex[top - 2], convex[top - 1], convex[top - 2], p[i%n]) < 0)--top;convex[top] = p[i%n];++top;++i;}return top;
}
int main() {int num = 0;scanf("%d", &n);//读入点找到左下角的点for (int i = 0; i < n; ++i) {scanf("%lf%lf", &p[i].x, &p[i].y);if (p[i].y < p[num].y || p[i].y == p[num].y&&p[i].x < p[num].x)num = i;}swap(p[0], p[num]);//极角排序sort(p + 1, p + n, cmp);num = graham();double ans = 0;//求周长for (int i = 1; i < num; ++i)ans += getDistance(convex[i], convex[i - 1]);printf("%.0lf\n", ans);return 0;
}
-----------------------
题目:
poj1113
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
class point {
public:int x, y;point(const int &x=0, const int &y=0) :x(x), y(y) {}
};
int n;
point p[1005], convex[1005];
int cross(const point &a, const point &b, const point &c, const point &d) {return (b.x - a.x)*(d.y - c.y) - (b.y - a.y)*(d.x - c.x);
}
bool cmp(const point &a, const point &b) {int temp = cross(p[0], a, p[0], b);if (!temp)return a.x < b.x;return temp > 0;
}
double getDistance(const point &a, const point &b) {return sqrt(1.0*(a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y - b.y));
}
int graham() {int top = 2, i = 2;convex[0] = p[0];convex[1] = p[1];while (i <= n) {while (top >= 2 && cross(convex[top - 2], convex[top - 1], convex[top - 2], p[i%n]) < 0)--top;convex[top] = p[i%n];++top;++i;}return top;
}
int main() {int r, num = 0;scanf("%d%d", &n, &r);for (int i = 0; i < n; ++i) {scanf("%d%d", &p[i].x, &p[i].y);if (p[i].y < p[num].y || p[i].y == p[num].y&&p[i].x < p[num].x)num = i;}swap(p[0], p[num]);sort(p + 1, p + n, cmp);num = graham();double ans = 0;for (int i = 1; i < num; ++i)ans += getDistance(convex[i], convex[i - 1]);ans += 2 * acos(-1.0)*r;printf("%.0lf\n", ans);return 0;
}
---------------------
有空补充一下快包和旋转卡壳
Graham Scan算法相关推荐
- 凸包Graham Scan算法实现
凸包Graham Scan算法实现 凸包算法实现点集合中搜索凸包顶点的功能,可以处理共线情况,可以输出共线点也可以不输出而只输出凸包顶点.经典的Graham Scan算法,点排序使用极角排序方式,并对 ...
- graham算法 java_凸包Graham Scan算法实现
凸包算法实现点集合中搜索凸包顶点的功能,可以处理共线情况,可以输出共线点也可以不输出而只输出凸包顶点.经典的Graham Scan算法,点排序使用极角排序方式,并对共线情况做特殊处理.一般算法是将共线 ...
- 计算几何入门 1.6:凸包的构造——Graham Scan算法
上文简要分析出了凸包构造问题算法的下界:O(nlogn),在此就引入一种下界意义上最优的算法:Graham Scan算法.这种算法可以保证在最坏情况下时间复杂度也不超过nlogn.我们先大致了解一下算 ...
- 计算几何--凸包之graham scan算法
Graham scan算法主要步骤: 找出所有已知点的y值最小,如果相同,取x值最小的点,作为基准点s. 以s为基准,所有的点按照与X轴夹角从小到大排序. 使用两个栈,一个记录已访问的点,一个记录未访 ...
- Graham Scan凸包算法
获得凸包的算法可以算是计算几何中最基础的算法之一了.寻找凸包的算法有很多种,Graham Scan算法是一种十分简单高效的二维凸包算法,能够在O(nlogn)的时间内找到凸包. 首先介绍一下二维向量的 ...
- Python:实现graham scan葛立恒扫描法算法(附完整源码)
Python:实现graham scan葛立恒扫描法算法 from __future__ import annotations from collections import deque from e ...
- 社区发现算法——SCAN算法
论文地址 该算法用于检测网络中的社区.桥节点和离群点.它基于结构相似性度量对顶点进行聚类.该算法特点是:速度快,效率高,每个顶点只访问一次. 主要贡献是能够识别出桥节点和离群点两种特殊点. 前面提到的 ...
- 操作系统 磁头引臂调度 SCAN算法 JAVA实现(二)
操作系统--磁头引臂调度SCAN算法 JAVA实现--双磁头引臂 具体要求 代码~ 说明 重要说明 具体要求 代码~ package com.guangluo.OS;import java.util. ...
- SCAN算法 | 磁头引臂调度问题 | 双磁头进阶 | Java实现(详细注释)
写在前面 欢迎讨论. 问题描述 用JAVA同步方法实现磁头引臂调度问题,采用SCAN算法. 要求:(1) 给出核心调度解法,用JAVA类实现,其中包含require(dest)和release()两个 ...
最新文章
- EasyUI--datebox设置默认时间
- 傅里叶变换时间复杂度
- AR、美颜、机器人:计算机视觉库几乎无所不在
- NYOJ 485 A*B Problem
- Oracle中Cursor介绍
- WebRTC视频数据流程分析
- 在Word XP中也能插入国际音标、拼音
- Tensorflow学习笔记4:分布式Tensorflow
- 字体模糊的解决办法 Windows Mobile
- 谈论为什么要写博客的重要性
- 解决VMware 小度wifi 驱动报错问题 Driver error
- gini指数与cart 决策树
- 如何设置vs2005的环境变量
- 基于角色的权限管理系统设计思路
- getinfo()java,Java Provider getInfo()用法及代碼示例
- css动漫效果库,10 个最佳 CSS 动画库
- matlab相机标定工具箱讲解,matlab 相机标定工具箱
- SLT容器使用技巧以及注意事项
- 大数据时代网络舆情与社会治理研究
- linux socket write()函数阻塞卡住线程问题(线程无法结束)write()非阻塞代码