Convex hull trick算法
来源:互联网 发布:nginx只允许域名访问 编辑:程序博客网 时间:2024/05/18 02:11
本文参考自http://wcipeg.com/wiki/Convex_hull_trick,内容包括我对wiki的一些简单翻译和个人的一些理解。
Convex hull trick是一种算法或者说数据结构,用于在一组线性函数(形如y=mi*x+bi)中,每次查询给以具体的x,可以快速求出最大/最小的y。
举个例子。
现在有y=4, y=4/3+2/3x, y=12-3x和 y=3-1/2x这四条直线,问当x取值为1时,这些线性函数的y里面的最小值。
四条直线如上图,可以发现当x=2时,直线y=4/3+2/3x有最小值,为2。
朴素的算法很容易就能想到,假设查询Q次,共有M条直线,那么时间复杂度就是O(QM)。
现在讲一下用Convex hull trick求最小值。
对于上面的几条直线,y=4始终不可能是最优解因此剔除,余下的只取它们为最小值的那段区间(上图绿色部分),它们的斜率是依次减小的,形成了一个凸包,它只有一个峰值。
因此,在去掉无关紧要的直线后,将余下的直线按照斜率降序排序,这样形成了N个区间,其中每段都是每条直线取最小值的那部分。如果我们可以确定每个区间的端点,那么这就变成了一个简单的问题:使用二分查询每个答案。
在前面已经发现,如果相关的线段已经确定和排序,那很明显它可以在O(lgN)内使用二分求解。因此,如果我们一次添加一条直线在我们数据结构中,然后再维护这个结构,将得到一个可行的算法:开始没有线(也可能一条或两条,取决于具体实现细节),每次添加一条直线直到整个的数据结构完成。
Convex hull trick空间复杂度为O(M),算法过程包括排序O(MlgM),Q次查询,每次是O(lgM),故时间复杂度是O((M+Q)lgM)。
最后贴一个模版。跟前面的例子不一样,这里是用来求最大值的,外部使用的时候直线要按斜率升序添加。要改成求最小值也很容易:二分改成求最小值,另外外部使用的时候直线要按降序依次添加。
struct Line{ LL m,b; LL get(LL x) { return m*x+b; }};struct ConvexHull{ int size; vector<Line> hull; ConvexHull(int maxSize) { hull=vector<Line>(maxSize+1); size=0; } bool isBad(int l1,int l2,int l3) { double left=1.0*(hull[l3].b-hull[l1].b)/(hull[l1].m-hull[l3].m); double right=1.0*(hull[l1].b-hull[l2].b)/(hull[l2].m-hull[l1].m); return left<right; } void addLine(LL m,LL b) { hull[size++]=Line{m,b}; while(size>2&&isBad(size-3,size-2,size-1)) { hull[size-2]=hull[size-1]; --size; } } LL query(LL x) { int l=0,r=size-1; while(l<r) { int m=(l+r)/2; if(hull[m].get(x)<=hull[m+1].get(x)) l=m+1; else r=m; } return hull[l].get(x); }};
- Convex hull trick算法
- Convex hull trick算法介绍
- codeforces 455E Convex hull trick
- convex hull
- Convex Hull
- convex hull
- 计算N维点集的Convex Hull的Quick hull算法
- Ouellet Convex Hull凸壳算法
- convex hull 算法之一:Graham Scan凸包算法
- 【算法导论】33.3:寻找凹包(Convex Hull)P:947
- POJ1113 Convex Hull/凸包 Graham scan算法
- Convex hull 之 Graham_scan(凸包检测算法)
- Convex hull凸包问题和Graham算法
- 大数据算法课程笔记2:2D Convex Hull
- UVA 11626 Convex Hull
- UVa 11626 - Convex Hull
- Convex hull: Graham scan
- HDU4697 Convex hull
- java网络编程
- Intellij idea 项目目录设置 与包的显示创建
- centos6 单用户模式和救援模式
- Android的init进程
- C#文件操作 追加、拷贝、删除、移动文件、创建目录 修改文件名、文件夹名
- Convex hull trick算法
- PostgreSQL 多路并行 xlog 设计
- html
- MySQL数据库入门练习200句
- 欧拉计划 41
- php的register_long_arrays可以关闭以提高性能
- mybatis逆向工程
- css
- 深入理解Java的接口和抽象类