更改了一下程序的错误。

Translation

找出凸包,然后逆时针输出每个点,测试数据中没有相邻的边是共线的。多测。

Solution

首先推销一下作者的笔记 由此进入>>>

明显是一道二维凸包模板。

在这里,我们简单讲一下二维凸包。

在平面上能包含所有给定点的最小凸多边形叫做凸包。

其定义为:对于给定集合 \(X\) ,所有包含 \(X\) 的凸集的交集 \(S\) 被称为 \(X\) 的 凸包

\(\qquad\qquad\) —— OI-Wiki

其实我们可以把凸包看成一个拿橡皮筋围成的一个图形。

假设有一个布满小凸起的板子:

我们要把这些凸起都围起来,怎么围呢?

显然,最简单方变的方法是这样:

但是,我们知道,橡皮筋是有弹力的,所以橡皮筋会往里缩,直到这样:

最外圈的凸起撑起了橡皮筋。

此时橡皮筋围成的多边形的顶点就是最外圈凸起所在的位置。

由此,我们就定义橡皮筋围成的图形为一个平面凸包。

那么,换一种定义,就为:

平面凸包是指覆盖平面上 \(n\) 个点的最小的凸多边形。

当然,我们发现在程序中却无法模拟橡皮筋收缩的过程,于是有了下文的诞生。

二维凸包的求法

斜率逼近法

其实这也是一种容易想到的算法,但是并不常用(代码复杂度高),所以我们省略带过。

Jarvis 算法

这其实是一种数学构造法

此算法的时间复杂度为 \(O(nm)\)。

但是,这个复杂度会爆炸。

于是我们伟大的 \(\sf OIer\) 就想到了 Graham 算法。

Graham 算法

Graham 算法的本质:

Graham 扫描算法维护一个凸壳,通过不断在凸壳中加入新的点和去除影响凸性的点,最后形成凸包。

凸壳:凸包的一部分。

此算法主要分为两部分:

  • 排序
  • 扫描
排序

我们先选择一个 \(y\) 最小的点(如 \(y\) 相同选 \(x\) 最小),记为 \(p_1\)。

剩下的点,按照极角的大小逆时针排序,记为 \(p_1,p_2,\dots, p_m\)。

我们按照排序结束时的顺序枚举每一个点,依次连线,这里可以使用一个栈来存储,每次入栈,如果即将入栈的元素与栈顶两个元素所构成了一个类似于凹壳的东西,那么显然处于顶点的那个点一定不在这个点集的凸包上,而他正好在栈顶,所以把它弹出栈,新点入栈。

扫描

(下列所说的左右等是指以上一条连线为铅垂线,新的连线偏移的方向)

刚开始,我们的点集是这样的:

\(p_1\) 为起始点。

随后,\(p_2\) 准备入栈,由于栈元素很少,所以可以入栈。

再看 \(p_3\),因为 \(p_3\) 向左,符合凸包条件,入栈。

随后 \(p_4\) 也一切正常,依然向左,入栈。

\(p_5\) 依然向左,入栈。

到 \(p_6\) 时,我们发现了点问题,就是不再是向左了,而是向右了,所以我们此时要将 \(p_5\) 出栈,\(p_6\) 入栈。

入栈后,我们发现,相对于 \(p_4\),\(p_6\) 依然是向右的,所以我们还要把 \(p_4\) 出栈,\(p_6\) 入栈。

接下来 \(p_7\) 没有问题。

\(p_8\) 时,我们发现,也是向右的,所以将 \(p_7\) 出栈,\(p_8\) 入栈。

接下来 \(p_9\) 正常,入栈。

最后,我们再把最后一个点和第一个点连起来。

此时,我们的 Graham 算法的全过程就结束了。

扫描的时间复杂度:\(O(n)\)。

但是不可能那么优秀,还要加上排序的时间复杂度:\(O(n\log n)\)。

所以总时间复杂度为 \(O(n \log n)\)。

可见此算法相比之前的算法优秀的多。

这道题,我们就用 Graham 算法求凸包。

直接按照 Graham 算法思路一步一步走即可。

Code

/*
Problem:UVA681
Date:02/07/20 14:56
*/
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<string>
#define line cout << endl
using namespace std;
const int NR = 1e6 + 5;
int t;
int n;
struct point {
int x, y;
};
point p[NR], ps[NR];
double dis (point pa, point pb) {
return sqrt (1.0 * (pb.x - pa.x) * (pb.x - pa.x) + 1.0 * (pb.y - pa.y) * (pb.y - pa.y));
}
int cp (point pa1, point pa2, point pb1, point pb2) {
return (pa2.x - pa1.x) * (pb2.y - pb1.y) - (pb2.x - pb1.x) * (pa2.y - pa1.y);
}
bool cmp (point px, point py) {
if (px.x == py.x && px.y == py.y) return false;
int num = cp (p[1], px, p[1], py);
if (num > 0) return true;
if (num == 0 && dis (p[0], px) < dis (p[0], py)) return true;
return false;
}
int convex_hull () {
sort (p + 2, p + n + 1, cmp);
ps[1] = p[1];
int h = 1;
for (int i = 2; i <= n; i++) {
while (h > 1 && cp (ps[h - 1], ps[h], ps[h], p[i]) <= 0) {
h--;
}
h++;
ps[h] = p[i];
}
ps[h + 1] = p[1];
return h;
}
void _memset () {
memset (p, 0, sizeof p);
memset (ps, 0, sizeof ps);
return;
}
int main () {
// freopen ("UVA681.in", "r", stdin);
// freopen ("UVA681.out", "w", stdout);
cin >> t;
cout << t << endl;
while (t--) {
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> p[i].x >> p[i].y;
if(i != 1 && p[i].y < p[1].y) {
swap (p[i].y, p[1].y);
swap (p[i].x, p[1].x);
}
}
if (t >= 1) {
int a;
cin >> a;
}
int h = convex_hull ();
cout << h + 1 << endl;
for (int i = 1; i <= h; i++) {
cout << ps[i].x << " " << ps[i].y << endl;
}
cout << ps[1].x << " " << ps[1].y << endl;
if (t >= 1) {
cout << "-1" << endl;
}
_memset ();
}
return 0;
}

【题解】「UVA681」Convex Hull Finding的更多相关文章

  1. 【题解】「MCOI-02」Convex Hull 凸包

    题目戳我 \(\text{Solution:}\) \[\sum_{i=1}^n \sum_{j=1}^n \rho(i)\rho(j)\rho(\gcd(i,j)) \] \[=\sum_{d=1} ...

  2. 【题解】「UVA11626」Convex Hull

    凸包模板题. 之前写过拿 Graham 算法求凸包的,为了不重复/多学点知识,那这次拿 Andrew 算法求凸包吧qaq *此文章所有图片均为作者手画. Andrew 算法 假设我们有这些点: 首先把 ...

  3. P6810 「MCOI-02」Convex Hull 凸包

    Link 一句话题意: 求出 \(\displaystyle\sum_{i=1}^{n}\sum_{j=1}^{m}\tau(i)\tau(j)\tau(gcd(i,j))\) 前置知识 \(diri ...

  4. 题解 「HDU6403」卡片游戏

    link Description 桌面上摊开着一些卡牌,这是她平时很爱玩的一个游戏.如今卡牌还在,她却不在我身边.不知不觉,我翻开了卡牌,回忆起了当时一起玩卡牌的那段时间. 每张卡牌的正面与反面都各有 ...

  5. 题解 「SCOI2016」萌萌哒

    link Description 一个长度为 $ n $ 的大数,用 $ S_1S_2S_3 \ldots S_n $表示,其中 $ S_i $ 表示数的第 $ i $ 位,$ S_1 $ 是数的最高 ...

  6. 题解 「SDOI2017」硬币游戏

    题目传送门 Description 周末同学们非常无聊,有人提议,咱们扔硬币玩吧,谁扔的硬币正面次数多谁胜利. 大家纷纷觉得这个游戏非常符合同学们的特色,但只是扔硬币实在是太单调了. 同学们觉得要加强 ...

  7. 题解 「ZJOI2018」历史

    题目传送门 Description 九条可怜是一个热爱阅读的女孩子. 这段时间,她看了一本非常有趣的小说,这本小说的架空世界引起了她的兴趣. 这个世界有 \(n\) 个城市,这 \(n\) 个城市被恰 ...

  8. 题解 「BZOJ3636」教义问答手册

    题目传送门 Description 作为泉岭精神的缔造者.信奉者.捍卫者.传承者,Pear决定印制一些教义问答手册,以满足泉岭精神日益增多的信徒.Pear收集了一些有关的诗选.语录,其中部分内容摘录在 ...

  9. 题解「BZOJ4310」跳蚤

    题目传送门 Description 现在有一个长度为 \(n\) 的字符串,将其划分为 \(k\) 段,使得这 \(k\) 段每一段的字典序最大子串中字典序最大的字符串字典序尽量小.求出这个字符串. ...

随机推荐

  1. Netlink 内核实现分析 4

    netlink 库函数: http://www.infradead.org/~tgr/libnl/doc/core.html#core_netlink_fundamentals #define NET ...

  2. C/C++中内存对齐问题的一些理解(转)

    内存对齐指令 一般来说,内存对齐过程对coding者来说是透明的,是由编译器控制完成的 如对内存对齐有明确要求,可用#pragma pack(n)指定,以n和结构体中最长数据成员长度中较小者为有效值 ...

  3. Dubbo 接口,导出 Markdown ,这些功能 DocView 现在都有了!

    前言 自从 DocView 发布了简陋的第一版之后,就不断地有小伙伴提建议意见等等,希望扩展各种功能.这不,时隔两周,DocView 又发布了新版本,本次的更新主要涉及到支持 Dubbo,以及支持导出 ...

  4. 【鸿蒙应用开发】使用确切位置布局(PositionLayout)实现登录页面

    上一节我们了解了PositionLayout(确切位置布局,我更倾向于称为绝对布局),虽然应用场景稀少.维护不方便,但是该有的示例还是不能少. UI图拆解及代码实现 这个界面我们是不是很熟悉,打开浏览 ...

  5. Windows常用的网络命令

    命令 说明 ipconfig 查看网络配置的信息 ping 测试网络是否连通 tracert 网络诊断工具,可以列出分组经过的路由节点 net 有添加用户.开启服务等功能 netstat 显示协议统计 ...

  6. Spring Cloud Netflix Eureka(注册中心)

    Eureka简介 Eureka是Netflix开发的一个Service Discovery组件,spring cloud将其整合用来做服务注册中心,Eureka包括两部分Eureka Server 和 ...

  7. ctf-工具-binwalk

    binwalk在玩杂项时是个不可缺的工具.1.最简单的,在玩隐写时,首先可以用它来找到其中的字符串例如:在铁人三项,东北赛区个人赛中,有一道题它直接给了一个文件,没有后缀,不知道是什么文件先binwa ...

  8. spark任务执行流程

    standlone模式 yarn模式 对比:

  9. 面试阿里,首先要掌握的 Java 泛型,帮你一次性搞懂!

    引言 泛型是Java中一个非常重要的知识点,在Java集合类框架中泛型被广泛应用.本文我们将从零开始来看一下Java泛型的设计,将会涉及到通配符处理,以及让人苦恼的类型擦除. 泛型基础 泛型类 我们首 ...

  10. 通过RayFire为图形添加二次破碎效果

    在完成3D建模之后,RayFire能帮助用户制作多种类型的破碎效果,如均匀碎片.放射状碎片.木碎等效果.另外,用户还可以利用RayFire的碎片选取功能,为图形进行二次破碎,以达到增加局部碎片的效果. ...