凸包

初学算法

本秂侑毒 提交于 2020-04-09 11:12:10
所谓凸包,就是 一个计算几何(图形学)中的概念。用不严谨的话来讲,给定二维平面上的点集,凸包就是将最外层的点连接起来构成的凸多边型,它能包含点集中所有的点。维基百科对集合X的凸包(Convex Hull)有四个定义,分别为: The (unique) minimal convex set containing X --- 包含集合X的最小凸集合 The intersection of all convex sets containing X --- 所有包含集合X的凸集合的交集 The set of all convex combinations of points in X . --- 集合X中所有点的凸组合的集合 The union of all simplices with vertices in X . --- 集合X中所有单一顶点的集合 对于二维凸包,不如我们把平面上的一些点想象为“钉子”,而你正将一个橡皮筋撑的足够大,以至于所有“钉子”都在你的橡皮筋包围的区域里。现在我们松开它。“啪”的一声,橡皮筋会尽可能的收缩到极致,而这时撑起橡皮筋的这些“钉子”构成的集合, 也就是凸包。 通过观察,我们可以知道“最左”和“最右”的两个点一定在构成凸包的集合里。而Garham's Scan算法也正是注意到了这点。另外,如果我们按照顺时针方向观察凸包,如P->Q->R

opencv图像轮廓

六月ゝ 毕业季﹏ 提交于 2020-04-08 07:06:11
最小外接圆 函数 cv2.minEnclosingCircle() 可以帮我们找到一个对象的外切圆。它是所有能够包括对象的圆中面积最小的一个。 案例:现有下面这样一张图片,要求将图片中心的花朵标记出来。 代码: import numpy as np import cv2 as cv img=cv.imread("image.jpg",0) #为了显示方便,这里将图片进行缩放 x,y=img.shape img=cv.resize(img,(y//2,x//2)) #将图片二值化,由于前景物体是黑色的,因此在二值化时采用cv.THRESH_TOZERO_INV这种方式 ret,thresh=cv.threshold(img,127,255,cv.THRESH_TOZERO_INV) #寻找图片中的轮廓,mode=cv.RETR_EXTERNAL,这是为了寻找最外层的轮廓 im,contour,hierarchy=cv.findContours(thresh,cv.RETR_EXTERNAL,cv.CHAIN_APPROX_SIMPLE) #cv.minEnclosingCircle函数的参数要求是ndarray类型,因此这里将找到的 # 轮廓中的所有的点存放在一个列表中,然后使用这个列表创建数组 point_list=[] for i in contour: for j in i:

Minimum dot product query

我的未来我决定 提交于 2020-03-29 04:00:32
Minimum dot product query (最小点积查询) : 若有一个二维向量集合V, 其大小为m. 那么在集合V上的一次最小点积查询即是说任意输入一个向量x, 返回在V中与x的点积最小的元素以及相应的点积,即 min{dot(x, vi) | vi 属于 V}。 这个问题是在 cstheory.stackexchange 上面看到的。楼主提出的问题原本是n维的最小点积查询,然后顺便提了下如果n=2, 则“immediate”就能得到一个(logm)^2的算法。我想了半天不知道他这个(logm)^2的复杂度是怎么弄出来的,但是事际上若n=2, 其实马上可以得到一个logm的算法。 首先一个观察是x的长度并不影响最后的结果(忽略那个||x||倍的缩放),所以可以假设x均为单位向量, 于是任意dot(vi, x)即是vi在x方向上的投影。这就给了我们一个启发:最小点积只能在V的凸包顶点处获得。 图1: V(黑色)与x(蓝色) 于是可以先求得V的凸包, 然后就将问题转化到求一个凸包投影到某个方向上后的端点。 图2: V 的凸包, 以及投影到x方向的最小点 如果凸包的边向量依次形成一个序列E,那么求凸包投影到x方向上的最小点即相当于将x旋转90度后(见图2中红色箭头)插入到E中的合适位置上。这可以通过二分法来得到,只是需要定义一个合适的序。这个序可以用叉乘来定义

UVa 11168 (凸包+点到直线距离) Airport

百般思念 提交于 2020-03-27 09:56:01
题意: 平面上有n个点,求一条直线使得所有点都在直线的同一侧。并求这些点到直线的距离之和的最小值。 分析: 只要直线不穿过凸包,就满足第一个条件。要使距离和最小,那直线一定在凸包的边上。所以求出凸包以后,枚举每个边求出所有点到直线的距离之和得到最小值。 点到直线距离公式为: 因为点都在直线同一侧,所以我们可以把加法“挪”到里面去,最后再求绝对值,所以可以预处理所有点的横坐标之和与纵坐标之和。当然常数C也要记得乘上n倍。 已知两点坐标求过该点直线的方程,这很好求不再赘述,考虑到直线没有斜率的情况,最终要把表达式中的分母乘过去。 1 //#define LOCAL 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <cmath> 6 #include <vector> 7 using namespace std; 8 9 struct Point 10 { 11 double x, y; 12 Point(double x=0, double y=0):x(x), y(y) {} 13 }; 14 typedef Point Vector; 15 Point operator + (Point A, Point B) 16 { 17 return Point(A.x+B.x, A.y+B

UVA10256 The Great Divide

老子叫甜甜 提交于 2020-03-26 10:51:22
题意 PDF 分析 就判断两个点集的凸包相离即可。 需要满足如下两个条件: 两凸包上任意两条线段不相交。 两凸包上任意一点不在另一凸包的内部。 时间复杂度 \(O(T n m)\) #include<iostream> #include<cstdio> #include<cstdlib> #include<cmath> #include<set> #include<map> #include<queue> #include<stack> #include<algorithm> #include<bitset> #include<cassert> #include<ctime> #include<cstring> #define rg register #define il inline #define co const template<class T>il T read() { rg T data=0; rg int w=1; rg char ch=getchar(); while(!isdigit(ch)) { if(ch=='-') w=-1; ch=getchar(); } while(isdigit(ch)) { data=data*10+ch-'0'; ch=getchar(); } return data*w; } template<class T>T read(T

UVa 11168 Airport , 凸包

雨燕双飞 提交于 2020-03-26 10:40:47
题意: 给出平面上n个点,找一条直线,使得全部点在直线的同側。且到直线的距离之平均值尽量小。 先求凸包 易知最优直线一定是凸包的某条边,然后利用点到直线距离公式进行计算。 #include<cstdio> #include<cstring> #include<vector> #include<cmath> #include<algorithm> #include<iostream> using namespace std; struct Point { int x, y; Point(int x=0, int y=0):x(x),y(y) {} }; typedef Point Vector; Vector operator + (const Vector& a, const Vector& b) { return Vector(a.x+b.x, a.y+b.y); } Vector operator - (const Vector& a, const Vector& b) { return Vector(a.x-b.x, a.y-b.y); } Vector operator * (const Vector& a, double p) { return Vector(a.x*p, a.y*p); } Vector operator / (const Vector& a,

求凸包

若如初见. 提交于 2020-03-04 19:53:19
写一个程序,实现凸包问题的蛮力算法。 请使用蛮力法而不是其他方法,不然你可能会受到分数的制裁。期待的时间复杂度是​O(n^3) 输入格式 输入数据第一行含有一个整数​n [1,200],表示点的数量。 接下来n​行,每行包括一个 整点 的坐标(xi,yi) [-1000,1000]​。 输出格式 输出共一行,表示这些点的凸包的长度,当相对或者绝对误差在10^-6​以内时,你的答案将被判定为正确。 测试输入 期待的输出 时间限制 内存限制 额外进程 测试用例 1 以文本方式显示 4↵ 0 0↵ 0 1↵ 1 1↵ 1 0↵ 以文本方式显示 4↵ 1秒 153600KB 0 #include<stdio.h> #include<math.h> #include<stdlib.h> int main() { int n,p[200][2],k,i,j,f1,f2,f3,a,b,c; double d,total=0; scanf("%d",&n); for(i=0;i<n;i++) { scanf("%d %d",&p[i][0],&p[i][1]); for(j=0;j<i;j++) { if((p[i][0]==p[j][0])&&(p[i][1]==p[j][1])) { n--; i--; } } } if(n==1) total=0; else { for(k=0;k<n-1

Lab1-实验心得

痞子三分冷 提交于 2020-03-04 09:33:13
一、Magic Square 相对路径 这部分遇到的第一个问题是输入矩阵的文本找不到,后来经过查资料和测试发现,相对路径应该是Sting path=“src//P1//txt//”+“文件名”,在路径开始时用./src和src均可,/src不行。 非法字符排除 最初在写代码的时候直接将所有的矩阵按行读入后,进行tab分割,并转化为整形存进二维数组,但是对于有不是用tab隔离的文件或包含小数的文件,程序会报错。最终的解决方式是按行读入文件后,首先对每行字符串进行判断,如果字符中存在除数字和tab外的其它字符(如“-”,“.”“ ”等)表示输入不合法,跳过后续步骤判断“不是魔方”,如通过了此次判断,则用tab对字符串进行分割,将每个分割后的字符串转换为整形字符存入数组,在全部读入后进行求和和比较。 Git提交 这部分在提交时txt文件夹在目录下始终是灰色文件夹的状态,不能打开。我上网搜索了一下原因,有很多说是因为这个文件夹下有git相关文件,删除就可以。但是我的文件夹下(包括隐藏内容)只有六个.txt文件,最后采取了先把文件移到其他文件夹下,最后再复制粘贴的方法。但是还是没有从根本解决这个问题,以后会继续查资料找到问题的原因。 二、Turtle Graph 凸包问题 这是这次实验困扰我时间最长的一个问题,因为没有接触过凸包算法,几何的功底也比较薄弱(捂脸哭),所以这部分对我来说很有难度

省选模拟(29-)

断了今生、忘了曾经 提交于 2020-02-25 22:43:23
省选模拟31 1.Skip 树状数组+静态凸包 我们先写出来裸 \(O(n^2)\) dp. 发现calc(i,j)中有ij形式的成分. 果断凸包维护. 把(j,val(j))看作点,题目要求截距最大. 维护上凸包. 打完后发现样例一个也过不去. 原来转移有条件:满足 \(a\) 单调递增. 那么就维护树状数组而后在 \(log\) 个凸包里查询,修改. \(O(nlog^2)\) 但是Kai586123的做法是按照a排序而后cdq一下. 按横坐标归并一下左右区间,然后扫到左区间的点建凸包,扫到右区间的点二分斜率 似乎不是 更新答案. 因为转移只会按照a升序转移,所以这样做是对的. 2.String dp 很遗憾最后没有能打出来. 先考虑80分状压dp做法的思路. 其实这个思路很朴素,只是我认为很难打. 依次枚举每个位置选的是哪种字符. 然后计算出来在前t位确定的情况下后面有多少种情况. 如果当前就>n就说明这一位不能再往下填了. 考虑怎么计算在已知前t位的情况下计算后面的情况数. 设现在已确定cnt种颜色.显然k>=cnt才行. 然后对于k-cnt的剩下的颜色随便选就行,反正我们并不关注. 然后对这k种颜色全排列. 这也是我意想不到的地方. 我没想到k=8支持这种骚操作. 现在就找到所有这k个位置的颜色还剩多少个能用. 再记录一下上个位置是谁就可以记忆化dp了. 想要ac的话.

ZOJ3537 Cake(区间dp+凸包判断)

为君一笑 提交于 2020-02-20 13:30:13
网上很多区间dp的代码是记忆化搜索的,还有些说这种区间dp必须倒序枚举 其实没有必要倒序,我们只需要按正常的区间dp的定义,第一维是长度,第二维枚举起点,第三维枚举断点即可 判断凸包的方法就是跟网上一样的常用方法Graham #include <iostream> #include <cstdio> #include <cmath> #include <cstring> #include <algorithm> using namespace std; const int maxn = 1005; const int inf = 1000000000; struct node { int x, y; } p[maxn], save[maxn], tmp[maxn]; int cost[maxn][maxn], n, m; int dp[maxn][maxn]; int dis(node p1, node p2, node p0) { return (p1.x-p0.x) * (p2.y-p0.y) - (p2.x-p0.x) * (p1.y-p0.y); } bool cmp(const node &a, const node &b) { if (a.y == b.y) return a.x < b.x; return a.y < b.y; } int Graham(node *p