凸包

算分-GEOMETRIC ALGORITHMS

半世苍凉 提交于 2020-02-08 19:11:03
Plane-Sweep:   平面扫描是二维的几何问题产生的算法范式。它的想法是用一条直线去扫描并且对于遇到的第一个数据进行处理。我们用这个想法解决三个问题:构造一些点的凸包,对凸包进行三角剖分,检测直线的交叉点。   首先介绍了凸包。设S是平面中给定两个坐标值的一系列点的集合,S的凸包记作convS,是S的所有凸集中最小的一个。把点想象成板子上的钉子,然后用一个橡皮筋在外面的钉子周围绕一圈,放手之后橡皮筋自然会跟踪凸包的边界。为了构造凸包,我们用一条直线从左到右扫描平面,直线左边的顶点都是处理好的,直线右边的点是待处理的。我们按横坐标对点进行排序为x1,x2,...,xn;然后选择前三个点用逆时针的方式形成一个三角形为x1x2x3或者是x1x3x2;对于i = 4 to n,我们按照一下方式加入xi,过xi作两条直线,要求它们可以支持这个凸包(理解成夹住凸包),然后连接xi和对应的两个顶点,就可以了。这三步完成之后就形成了凸包,下面是一个例子:      这个图展示的是加入6的这个点的过程,作了两条直线63和65,支撑了这个凸包,然后连接起来就形成了新的凸包。   然后介绍了定向,如何决定访问三个点的顺序是逆时针还是顺时针呢?其实只要结合行列式就可以了,因为可以通过行列式来计算面积,根据面积的正负来判断当前的方向。   接着介绍了寻找支撑线(支持线)的方法

P1452 旋转卡壳

偶尔善良 提交于 2020-02-02 04:13:10
题面 给定平面n个点,求凸包直径(输出凸包直径的平方) 2 < = n < = 50000 2<=n<=50000 2 < = n < = 5 0 0 0 0 (实测存在一列点构成直线的数据) 分析 凸包直径:凸包两两顶点间最远的距离 容易想到O(n 2 )的方法, 求出凸包 后遍历顶点对求距离max即可 但有更优的做法,遍历的一个点移动一次,其对面的点(对踵点)移动的幅度并不会太大,并且旋转方向相同(同顺时针或同逆时针),所以其实存在O(N)的做法。 这种遍历一般有两种:点-点遍历,边-点遍历: 第二种在代码上实现更容易(第一种貌似有特例,如特别扁的图形,会失去长度的单峰性) 过程即start边在凸包上移动,分别找出每个start边的最远opposite点。这个最远可以用三角形面积来衡量,如图上的那样,根据平行线的知识,过其他顶点作start边的平行线,最远的平行线可以使三角形面积最大,也就是最远的点。这时计算这个最远点与start两端点的距离取max即得出当前start边下能得到的最大直径。对所有start边下的直径取max即是全局最大直径。 如何快速找出对每一个start最远的opposite?如果单纯遍历仍然会落入O(n 2 )。而通过观察同一start下三角形的面积是一个单峰函数(平行线从近到远再到近),并且已知start移动一次,这个峰移动不会太大,而且是同向移动

The Fortified Forest POJ - 1873 (1999 WF,凸包+二进制枚举)

拥有回忆 提交于 2020-02-02 02:56:33
题目链接: https://vjudge.net/problem/POJ-1873 题意:传说中WF水题。。。。给你树的每个坐标,价值以及建造长度,要求你砍掉一些树来把其他数都围起来,来求砍掉哪些树和多余的砍掉的木材长度,达到最优价值最少 思路:用二进制枚举所有砍树的情况(2^n),然后算出没被砍的树的凸包和周长,当砍掉树的建造周长大于等于凸包周长时,记录价值,当下一次价值大于该价值时可以直接跳过不用考虑,每次符合条件更新即可 1 // 2 // Created by HJYL on 2020/2/1. 3 // 4 #include<iostream> 5 #include<cstring> 6 #include<cstdio> 7 #include<cmath> 8 #include<algorithm> 9 using namespace std; 10 const double eps=1e-8; 11 const int maxn=100; 12 const int INF=0x3ffff; 13 int dcmp(double x) 14 { 15 if(fabs(x)<eps) 16 return 0; 17 return x<0?-1:1; 18 } 19 struct Point { 20 double x, y; 21 int value; 22 int len

目标表达(基于边界的表达)

拥有回忆 提交于 2020-02-01 05:49:02
一、基于边界的表达 技术分类: (1) 边界点集合:各点间没有顺序 (2) 参数边界:将目标的轮廓线表示为参数曲线 (3) 曲线逼近:用几何基元来近似 1、地标点: 就是单个(x,y)坐标点 一种近似表达方法,点越多近似越好 2、链码 : 用线段表示边界上相邻两个象素之间的联系每个线段的长度固定而方向数目取为有限起点用坐标表示,其余点只用接续方向。 简单的说取一个头,后面的点都是距离这个点按照位置偏移。 链码归一化: ①起点归一化 (将链码看作由方向数构成的自然数选取值最小的自然数顺序) ②旋转归一化(利用链码的一阶差分差分码不随轮廓旋转而变化利用链码的一阶差分差分码不随轮廓旋转而变化 ) 链码平滑: ( 将原始的链码序列用较简单的序列代替 ) 虚线箭头:原始的在象素p和q之间的8-连通链码 实线箭头:用来替换原始序列的新序列 缝隙码: 连接相邻轮廓象素边缘的中点 3、边界段 简化表达,把边界分解成若干段分别表示可节省表达数据量(针对性强)借助凸包(包含目标的最小凸形)概念 根据凸包把边界 分解成:目标(象素集合S分解) 凸包:包含S的最小凸形 H凸残差:D = H –S 重要思想:跟踪边界H,每个进入D或者出去D的点就是一个分段点。 4、边界标志 把2-D边界用1-D的较易描述的函数形式来表达 具体方法有以下几种: 1、距离为角度的函数。(角度为X,距离或者说半径为Y)

P2742 【模板】二维凸包 / [USACO5.1]圈奶牛Fencing the Cows

本秂侑毒 提交于 2020-01-22 03:00:15
P2742 【模板】二维凸包 / [USACO5.1]圈奶牛Fencing the Cows](https://www.luogu.com.cn/problem/P2742) 题目描述 农夫约翰想要建造一个围栏用来围住他的奶牛,可是他资金匮乏。他建造的围栏必须包括他的奶牛喜欢吃草的所有地点。对于给出的这些地点的坐标,计算最短的能够围住这些点的围栏的长度。 输入格式 输入数据的第一行包括一个整数 N。N(0 <= N <= 10,000)表示农夫约翰想要围住的放牧点的数目。接下来 N 行,每行由两个实数组成,Xi 和 Yi,对应平面上的放牧点坐标(-1,000,000 <= Xi,Yi <= 1,000,000)。数字用小数表示。 输出格式 输出必须包括一个实数,表示必须的围栏的长度。答案保留两位小数。 输入输出样例 输入 #1 4 4 8 4 12 5 9.3 7 8 输出 #1 12.00 凸包详解 # include <stdio.h> # include <cmath> # include <algorithm> using namespace std ; struct node { double x , y ; } p [ 10005 ] , s [ 10005 ] ; double check ( node a1 , node a2 , node b1 , node b2

Graham算法

守給你的承諾、 提交于 2020-01-15 07:24:19
前言:本菜鸡的第一篇算几,记录一下我有多菜 Graham算法 一种凸包算法,扫描部分的时间复杂度为 O ( n ) \mathcal{O}(n) O ( n ) ,总的时间复杂度 O ( n l o g n ) \mathcal{O}(nlogn) O ( n l o g n ) 原理:从点集中先找出一个最左下方的点,易证这个点肯定在凸包上,然后以这点为极点,将所有点根据与这点的极角进行排序,并且同时使用一个栈结构维护凸包上的点。按照极角序依次将当前点与栈顶的两个点作拐向判断:若右拐,则将当前点加入栈中,否则将栈顶点弹出。当点集遍历完之后,还在栈中的点就是凸包上的点。 算法步骤 对所有点进行排序,选择 x x x 坐标最小的点作为极点,即找到第一个一定在凸包上的点 bool cmp1 ( const Pnt & a , const Pnt & b ) { return a . x != b . x ? a . x < b . x : a . y < b . y ; } 将其余所有点按照极角排序,在极角相同的情况下比较与极点的距离,按极角序依次处理每一个点 inline bool cmp2 ( const Pnt & st , const Pnt & ed ) { //按极角排序 int del = p [ st ] * p [ ed ] ; if ( del != 0 )

Codeforces 678F Lena and Queries

风流意气都作罢 提交于 2020-01-12 19:39:20
题意: 你有一个点集,有三种操作: 往集合里插入一个点 \((x, y)\) 从集合中删除第 \(i\) 次操作插入的点 对于给出的 \(q\) ,询问点集中 \(x \cdot q + y\) 的最大值 分析: 先不考虑插入删除操作,对于一个给定的点集,如何寻找 \(x \cdot q + y\) 最大值 这是一个线性规划的问题,只是可行域变成了离散的点。 设 \(x \cdot q + y = z\) ,其中 \(z\) 是优化目标。 \(y = -q \cdot x + z\) ,使得经过点 \((x, y)\) 斜率为 \(-q\) 的直线的截距最大。 那么作为最优解的点一定在点集的凸包上,所以可以用单调栈求出凸包,然后三分求最大值。 因为每次操作都可能导致点集发生变化,不可能每次都求一遍凸包。 每个节点对应一个生存期 \([L, R]\) ,即在第 \(L\) 次操作到第 \(R\) 次操作中点集中有该点。 然后把它插入到一个线段树的区间中,这样线段树的每个点都对应一段操作区间的一个点集。 用这个点集的凸包更新所有这个区间的询问。 #include <cstdio> #include <cstring> #include <algorithm> #include <vector> using namespace std; typedef long long LL;

斜率优化之凸包优化与李超线段树

馋奶兔 提交于 2019-12-28 11:05:12
文章目录 前言 凸包优化 第一步 第二步 最后一步 例一 转移方程 凸包优化 代码 例二 题目大意 转移方程 凸包优化 代码 李超线段树 思想 插入 查询 代码 例三 代码 例四 转移方程 怎么做 代码 前言 这种方法比传统斜率优化更快,更准,更狠。 凸包优化 一切形如 d p [ i ] = min ⁡ / max ⁡ { f 1 ( j ) ⋅ g 1 ( i ) + f 2 ( j ) } + g 2 ( i ) dp[i]=\min/\max\{f_1(j) \cdot g_1(i) + f_2(j)\} + g_2(i) d p [ i ] = min / max { f 1 ​ ( j ) ⋅ g 1 ​ ( i ) + f 2 ​ ( j ) } + g 2 ​ ( i ) 的转移方程,都可以凸包优化。 其中, f f f 为关于 j j j 的函数, g g g 为关于 i i i 的函数。 例如 d p [ i ] = min ⁡ { − 2 h j ⋅ h i + h j 2 + d p [ j ] } + a i + h i 2 dp[i] = \min\{-2h_j \cdot h_i + {h_j}^2 + dp[j]\} + a_i + {h_i}^2 d p [ i ] = min { − 2 h j ​ ⋅ h i ​ + h j ​ 2 + d p

[OJ#39]左手右手

风流意气都作罢 提交于 2019-12-26 17:41:21
[OJ#39]左手右手 试题描述 有 n 个人,每个人左右手上各写着一个整数。对于编号为 a 的人和编号为 b 的人, a 对 b 的好感度等于 a 左手上写的数字乘 b 右手上写的数字, a 和 b 的好感度差异等于 a 对 b 的好感度与 b 对 a 的好感度之差的绝对值。 现在,你要从这 n 个人中找出两个人使得他们的好感度差异最大。 输入 第一行一个整数 n 。 接下来 n 行,每行两个整数 a i , b i ,分别表示第 i 个人左右手上写的数字。 输出 输出一个整数表示好感度差异的最大值。 输入示例 5 9 -1 7 8 -2 4 9 -6 3 5 输出示例 114 数据规模及约定 2 ≤ n ≤ 10 5 , − 10 9 ≤ a i , b i ≤ 10 9 题解 首先我们可以发现两个人 i, j 的好感度差异就是两个向量 (a i , b i ) 和 (a j , b j ) 的叉积的绝对值。那么要让这个值最大,就是要选择两个向量使得它们围成的三角形面积最大。 我们不妨先枚举其中一个向量 x ,可以发现与它叉积绝对值最大的向量 y 一定在凸包上。我们做平行于向量 x 的直线,显然如果向量 y 的终点在直线上,这条直线离原点越远越好,所以一定是在凸包上的。 所以我们先处理出凸包,然后把所有向量按照极角排序,用旋转卡壳的方法去做就可以 O(n) 了。

计算几何-经典算法-凸包

本小妞迷上赌 提交于 2019-12-17 21:28:07
  在学习了一些有关计算机几何的基础知识和一些基本工具之后要快速的解决一些简单的几何问题,如两点之间的距离、两线段的交点个数等等是可以轻松应付的,但是对于复杂点的几何问题,我们还是要有更好的算法,这样才可以更高效的解决它。在这一篇中来总结 平面凸包 的 Graham算法; http://www.cnblogs.com/jbelial/ 平面凸包 : 定义: 对一个简单多边形来说,如果给定其边界上或内部的任意两个点,连接这两个点的线段上的所有点都被包含在该多边形的边界上或内部的话,则该多边形为凸多边形 。 在解决平面凸包下面介绍了两种算法: 一、 Graham 扫描法,运行时间为 O(nlgn) 。 二、 Jarvis 步进法,运行时间为 O(nh),h 为凸包中的顶点数。 例题 1 1 问题描述1: 2 求覆盖平面上n 个点的最小的凸多边形。也可以这样描述:给定一个连接的多边形,可能是凸多边形,也有可能是凹多边形。现在,你的任务就是编程求这个多边形的最小凸包。如果它本身是凸多边形,那么最小凸包就是它本身。 3 数据范围: 4 多边形顶点坐标X,Y 是非负整数,不超过512。 5 输入: 6 共有K 组数据,每组测试数据的点都是按逆时针顺序输入的,没有3 个点共线。 7 每组测试数据的第1 行是N,表示有N 个点。以下N 行,每行两个整数X,Y。 8 输出: 9