(模板)graham扫描法、andrew算法求凸包
凸包算法讲解:Click Here
题目链接:https://vjudge.net/problem/POJ-1113
题意:简化下题意即求凸包的周长+2×PI×r。
思路:用graham求凸包,模板是kuangbin的,算法复杂度O(nlogn)。
AC code:
// Author : RioTian
// Time : 20/10/21
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
using namespace std;
const int N = 1000;
const double Pi = acos(-1.0);
struct point {
double x, y;
point() : x(), y() {}
point(int x, int y) : x(x), y(y) {}
} list[N];
typedef point P;
int stack[N], top;
//计算叉积: p0p1 X p0p2
double cross(P p0, P p1, P p2) {
return (p1.x - p0.x) * (p2.y - p0.y) - (p2.x - p0.x) * (p1.y - p0.y);
}
//计算 p1p2的 距离
double dis(P p1, P p2) {
return sqrt((double)(p2.x - p1.x) * (p2.x - p1.x) +
(p2.y - p1.y) * (p2.y - p1.y));
}
//利用极角排序,角度相同则距离小排前面
bool cmp(P p1, P p2) {
auto tmp = cross(list[0], p1, p2);
if (tmp > 0)
return true;
else if (tmp == 0 && dis(list[0], p1) < dis(list[0], p2))
return true;
else
return false;
}
//输入,并把 最左下方的点放在 list[0] 。并且进行极角排序
void init(int n) {
int i, k = 0;
cin >> list[0].x >> list[0].y;
P p0 = list[0]; // p0 等价于 tmp 去寻找最左下方的点
for (int i = 1; i < n; ++i) {
cin >> list[i].x >> list[i].y;
if (p0.y > list[i].y || (p0.y == list[i].y && p0.x > list[i].x))
p0 = list[i], k = i;
}
list[k] = list[0];
list[0] = p0;
sort(list + 1, list + n, cmp);
}
//graham扫描法求凸包,凸包顶点存在stack栈中
//从栈底到栈顶一次是逆时针方向排列的
//如果要求凸包的一条边有2个以上的点
//那么要将while中的<=改成<
//但这不能将最后一条边上的多个点保留
//因为排序时将距离近的点排在前面
//那么最后一条边上的点仅有距离最远的会被保留,其余的会被出栈
//所以最后一条边需要特判
//如果要求逆凸包的话需要改cmp,graham中的符号即可
void Graham(int n) {
int i;
if (n == 1) top = 0, stack[0] = 0;
if (n == 2) top = 1, stack[0] = 0, stack[1] = 1;
if (n > 2) {
for (i = 0; i <= 1; i++) stack[i] = i;
top = 1;
for (i = 2; i < n; i++) {
while (top > 0 &&
cross(list[stack[top - 1]], list[stack[top]], list[i]) <= 0)
top--;
top++;
stack[top] = i;
}
}
}
int main() {
freopen("in.txt", "r", stdin);
// ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int N, L;
while (scanf("%d", &N) != EOF) {
init(N);
Graham(N);
double res = 0;
for (int i = 0; i < top; i++)
res += dis(list[stack[i]], list[stack[i + 1]]);
res += dis(list[stack[0]], list[stack[top]]);
res += 2 * Pi;
printf("%d\n", (int)(res + 0.5));
}
}
题目链接:https://www.luogu.com.cn/problem/P2742
题意:求凸包的周长。
思路:
这里用andrew算法来求,该算法与graham的区别是排序方法不一样,这里按x坐标从左到右排序,x相同的按y坐标从下到上排序。下列程序展示先求下凸包,再求上凸包。复杂度O(nlogn),但据说比graham的复杂度小一点。
AC code:
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
const int maxn = 1e5 + 5;
struct Point {
double x, y;
Point(double xx = 0, double yy = 0) : x(xx), y(yy) {}
};
double cross(Point p0, Point p1, Point p2) {
return (p1.x - p0.x) * (p2.y - p0.y) - (p2.x - p0.x) * (p1.y - p0.y);
}
//排序方法不同
bool cmp(Point a, Point b) {
if (a.x != b.x) return a.x < b.x;
return a.y < b.y; // y从小到大和从大到小都行
}
double dis(Point a, Point b) {
return sqrt((b.x - a.x) * (b.x - a.x) + (b.y - a.y) * (b.y - a.y));
}
Point list[maxn], stk[maxn];
int n, p;
double ans;
void andrew() {
p = 1;
stk[0] = list[0], stk[1] = list[1];
for (int i = 2; i < n; ++i) { //求下凸包
while (p > 0 && cross(stk[p - 1], stk[p], list[i]) <= 0) --p;
stk[++p] = list[i];
}
stk[++p] = list[n - 2];
for (int i = n - 3; i >= 0; --i) { //求上凸包
while (p > 0 && cross(stk[p - 1], stk[p], list[i]) <= 0) --p;
stk[++p] = list[i];
} //要注意栈尾和栈顶都是list[0]
}
int main() {
scanf("%d", &n);
for (int i = 0; i < n; ++i) scanf("%lf%lf", &list[i].x, &list[i].y);
sort(list, list + n, cmp);
andrew();
for (int i = 0; i < p; ++i) ans += dis(stk[i], stk[i + 1]);
printf("%.2f\n", ans);
return 0;
}
(模板)graham扫描法、andrew算法求凸包的更多相关文章
- 凸包模板——Graham扫描法
凸包模板--Graham扫描法 First 标签: 数学方法--计算几何 题目:洛谷P2742[模板]二维凸包/[USACO5.1]圈奶牛Fencing the Cows yyb的讲解:https:/ ...
- Andrew算法求二维凸包-学习笔记
凸包的概念 首先,引入凸包的概念: (有点窄的时候...图片右边可能会被吞,拉开图片看就可以了) 大概长这个样子: 那么,给定一些散点,如何快速地求出凸包呢(用在凸包上的点来表示凸包) Andrew算 ...
- nyoj-78-圈水池(Graham算法求凸包)
题目链接 /* Name:nyoj-78-圈水池 Copyright: Author: Date: 2018/4/27 9:52:48 Description: Graham求凸包 zyj大佬的模板, ...
- LA 4728 旋转卡壳算法求凸包的最大直径
#include<iostream> #include<cstdio> #include<cmath> #include<vector> #includ ...
- [poj1113][Wall] (水平序+graham算法 求凸包)
Description Once upon a time there was a greedy King who ordered his chief Architect to build a wall ...
- POJ 2187 Beauty Contest【旋转卡壳求凸包直径】
链接: http://poj.org/problem?id=2187 http://acm.hust.edu.cn/vjudge/contest/view.action?cid=22013#probl ...
- 计算几何 : 凸包学习笔记 --- Graham 扫描法
凸包 (只针对二维平面内的凸包) 一.定义 简单的说,在一个二维平面内有n个点的集合S,现在要你选择一个点集C,C中的点构成一个凸多边形G,使得S集合的所有点要么在G内,要么在G上,并且保证这个凸多边 ...
- poj 3348:Cows(计算几何,求凸包面积)
Cows Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 6199 Accepted: 2822 Description ...
- (模板)poj1113(graham扫描法求凸包)
题目链接:https://vjudge.net/problem/POJ-1113 题意:简化下题意即求凸包的周长+2×PI×r. 思路:用graham求凸包,模板是kuangbin的. AC code ...
随机推荐
- 随机梯度下降法(Stochastic gradient descent, SGD)
BGD(Batch gradient descent)批量梯度下降法:每次迭代使用所有的样本(样本量小) Mold 一直在更新 SGD(Stochastic gradientdescent)随机 ...
- Leetcode-剪枝
51. N皇后 https://leetcode-cn.com/problems/n-queens/ n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击. ...
- 064 01 Android 零基础入门 01 Java基础语法 08 Java方法 02 无参带返回值方法
064 01 Android 零基础入门 01 Java基础语法 08 Java方法 02 无参带返回值方法 本文知识点:无参带返回值方法 说明:因为时间紧张,本人写博客过程中只是对知识点的关键步骤进 ...
- NMOS和PMOS区别
在很多电路途中会出现NMOS和PMOS管,因为不是中文那么直接,都说管压降之类的,但其实它的导通很重要以及区别,关系到你点亮电子元件> 参考: 1.https://blog.csdn.net/l ...
- Linux就该这么学28期——开篇
2020.10.03 正式开始系统学习Linux之旅,希望能在老刘的带领下,掌握操作要领. 现将所学记录在此. 学习环境如下: VmwareWorkStation 15 --虚拟机软件 versio ...
- JVM系列【3】Class文件加载过程
JVM系列笔记目录 虚拟机的基础概念 class文件结构 class文件加载过程 jvm内存模型 JVM常用指令 GC与调优 Class文件加载过程 JVM加载Class文件主要分3个过程:Loadi ...
- Gearman实战第一弹:异步处理结算单
昨天梦回jm,醒来之后看着窗外万里晴空,想大声喊一句:爷青回! 我想起之前使用gearman的岁月.不知不觉也过了快5年,想总结一篇关于gearman的技术文章算是一种对青春的祭奠,再不写的话更少有p ...
- Windows 编程基础
1 Windows应用程序的分类 1.1 控制台程序 DOS程序,本身没有窗口,通过WINDOWS下的DOS窗口执行. 1.2 窗口程序 拥有自己的窗口,通过窗口可以和用户进行交互.(比如:记事本,画 ...
- 学习WebDav
目录 前言 初识WebDav 有哪些支持webdav的网盘? WebDAV的特性和优势 服务端的搭建 调用WebDav接口 PROPFIND方法 PROPPATCH方法 MKCOL方法 PUT方法 G ...
- Pycharm开发环境配置与调试
在Windows宿主机上搭建Ubuntu虚拟机的Pycharm开发环境,Ubuntu开启Samba服务,使用网络映射将Ununtu下Python项目工程路径映射到Windows下 创建Pycharm工 ...