凸包中的点(2D)


10

背景

有限数量点的凸包是包含所有点的最小凸多边形,无论是顶点还是内部。有关更多信息,请参见有关PGM的问题,该问题定义得很好

输入值

N+1N >= 3通过STDIN以下格式的2-D坐标()(也允许其他常见的高尔夫输入)(小数位数可以变化,但是您可以假定它保持“合理”,并且每个数字都可以表示为浮点数):

0.00;0.00000
1;0.00
0.000;1.0000
-1.00;1.000000

输出量

STDOUT如果列表中的第一个点((0.00;0.00000)在上面的示例中)位于其他N个点的凸包中,则打印到(或等效)真值(否则为等价)。

这是,因此以字节为单位的最短解决方案为准。

  • 边界案例:如果该点位于凸包的边界上(例如,在壳的外部边界的一侧或顶点上),则可以返回任何值(但不会崩溃),因为该概率为零事件(以任何合理的概率)。

  • 禁止使用用于解决几何问题的任何内容(语言,运算符,数据结构,内置或包)(例如Mathematica的ConvexHull)。允许使用通用数学工具(矢量,矩阵,复数等)。

测验


3
什么是“临时数据结构”?
DavidC

“基本职能/经营者”过于模糊。
xnor

@DavidCarraher:诸如多边形,三角形或线段(仅用于解决几何问题的任何东西)之类的东西。
亚历山德拉·哈尔姆

2
@AlexandreHalm您的编辑很有帮助。我认为“基本”一词不正确。我以为它将消除通用的内置函数,例如sortround。我认为只说没有专门为几何图形做的事情就更清楚了。但是,关于将两个列表作为向量相加的函数呢?还是找到复数参数(角度)的函数?
xnor

1
这就是Diamonds要求人们在发布新挑战之前请使用沙盒的原因
2015年

Answers:


9

40 39 34个字节

3 :'(o.1)<(>./-<./)12 o.y*+{.y'@:-

一个匿名二进位函数,将点p作为其参数之一,并将点列表P作为另一个参数(无论哪个参数无关紧要),如果p在或之外,则返回0or 1。在P的凸包内部。点pP中的点被视为复数。

  is_inside =: 3 :'(o.1)<(>./-<./)12 o.y*+{.y'@:-

  0.5j0.5  is_inside  0j0 0j1 1j0 1j1
1
  1.5j0.5  is_inside  0j0 0j1 1j0 1j1
0

要么...

Python 2,函数, 121 103,完整程序, 162

Python 3,149字节

import sys,cmath as C
p,q,*P=[complex(*eval(l.replace(*";,")))for l in sys.stdin]
A=[C.phase((r-p)/(q-p+(q==p)))for r in P]
print(max(A)-min(A)>C.pi)

通过STDIN以与原始帖子相同的格式输入输入,并打印一个布尔值,该值指示p是否在P的凸包中


说明

程序检测的最大值和最小值(符号)之间的差是否任何点之间的角度- [RPp,和一个固定的任意的点qP(我们只使用在第一点P),是小于180°。换句话说,它测试P中的所有点是否都包含在p周围的180°或更小的角度中。 p是在的凸包P当且仅当该条件为假。


以更多的字节为代价,我们可以使用类似的方法,该方法不需要我们显式地计算角度:请注意,上述条件等效于说且仅当存在时p位于P的凸包之外。一条从lp的线,使得P中的所有点都在l的同一侧。如果存在这样一条线,那么也有一条线入射到P中的一个(或多个)点(我们可以旋转l直到它碰到P中的一个点)。

为了(暂时)找到这条线,我们首先让l为穿过p的线和P中的第一个点。然后,我们遍历P中的其余点;如果其中一个点位于l的左侧(我们假设整个方向性,实际上左右无关紧要),我们将l替换为穿过p和该点的线,然后继续。在对所有P进行迭代之后,如果(且仅当)p在凸包之外,则P中的所有点都应在l的右侧(或上方)。我们通过第二遍检查P中的点来检查

Python 2,172字节

import sys
P=[eval(l.replace(*";,"))for l in sys.stdin]
x,y=P.pop(0)
C=lambda(a,b),(c,d):(a-x)*(d-y)-(b-y)*(c-x)>0
l=reduce(lambda*x:x[C(*x)],P)
print any(C(l,q)for q in P)


或者,为了做同样的事情在单次通过,让以最左的是任何两个点之间的维吾尔q- [R ,在P,使得q是向左的ř如果q是向左穿过pr的那一行。请注意,当且仅当P中的所有点都在通过p的某条线的同一侧时,即pP的凸包之外时,to-the-left-of才是P上的顺序关系。上述过程在P中找到最小值此顺序,即P中的“最左”点。无需执行两次遍历,我们可以在一次遍历中以相同顺序找到P点的最大值(即“最右边”的点)和最小值,并验证最小值在顶点的左侧。最大,即有效地,最左边的是传递的。

如果pP的凸包之外,这会很好地工作,在这种情况下,to-the-left实际上是一个顺序关系,但是当p在凸包内时可能会破裂(例如,尝试找出将如果运行此算法,则P中的点是正五边形的顶点,沿逆时针方向运行,p是其中心。如果要适应,我们将算法稍作改动:我们在P中选择一个点q,并等分P沿着穿过pq的线(即,我们在q周围划分P现在,我们有一个P的一个“左部分”和一个“右部分” ,每个部分包含在一个半平面中,因此,在每个部分的最左边是一个顺序关系;我们找到左边的最小值,右边的最大值,并如上所述进行比较。当然,我们不必在物理上将P分为两等分,我们可以在一次寻找最小和最大值的过程中简单地对P中的每个点进行分类。

Python 2,194个字节

import sys
P=[eval(l.replace(*";,"))for l in sys.stdin]
x,y=P.pop(0)
C=lambda(a,b),(c,d):(a-x)*(d-y)-(b-y)*(c-x)>0
l=r=P[0]
for q in P:
 if C(P[0],q):l=q*C(l,q)or l
 elif C(q,r):r=q
print C(l,r)

您是否有可能使您的解决方案(至少是Python的解决方案,我不知道J是否可以做到)从STDIN获得输入?我发现将解决方案与公平竞争环境进行比较会比较容易。假设输入已经是一组预格式化的复数或点集,这有点像是IMO。
亚历山德拉·哈尔姆

@AlexandreHalm添加了完整程序。
2015年

您应该将解决方案分为每种语言的一个答案。
Mego 2015年

4

八度,82 72字节

d=dlmread(0,";");i=2:rows(d);~isna(glpk(i,[d(i,:)';~~i],[d(1,:)';1]))&&1

这个想法是检查线性程序min {c'x:Ax = b,e'x = 1,x> = 0}是否具有解,其中e是所有矢量,A的列是A的坐标点云,b是测试点,c是任意的。换句话说,我们尝试将b表示为A列的凸组合。

要运行脚本,请使用 octave -f script.m <input.dat


2

R,207字节

d=read.csv(file("stdin"),F,";")
q=function(i,j,k)abs(det(as.matrix(cbind(d[c(i,j,k),],1))))
t=function(i,j,k)q(i,j,k)==q(1,i,j)+q(1,i,k)+q(1,j,k)
any(apply(combn(2:nrow(d),3),2,function(v)t(v[1],v[2],v[3])))

该脚本从STDIN获取其输入,例如Rscript script.R < inputFile

它从N最后一个点(最后一条线apply(combn(...)生成所有三角形,并使用t函数检查第一个点是否在三角形中。

t使用area方法来确定Uin 是否在ABC:(写入(ABC)的区域ABCUABCiff中(ABC) == (ABU) + (ACU) + (BCU)。另外,面积是使用行列式公式计算的(有关Wolfram的演示,请参见此处)。

我怀疑这种解决方案比其他解决方案更容易出现数字错误,但它适用于我的测试用例。


0

R,282字节

d=read.csv(file("stdin"),F,";")
p=function(a,b)a[1]*b[1]+a[2]*b[2]
t=function(a,b,c){A=d[a,];
U=d[1,]-A
B=d[b,]-A
C=d[c,]-A
f=p(C,C)
g=p(B,C)
h=p(U,C)
i=p(B,B)
j=p(U,B)
k=f*i-g*g
u=i*h-g*j
v=f*j-g*h
min(u*k,v*k,k-u-v)>0}
any(apply(combn(2:nrow(d),3),2,function(v)t(v[1],v[2],v[3])))

该脚本从STDIN获取其输入,例如Rscript script.R < inputFile

它从N最后一个点(最后一条线apply(combn(...)生成所有三角形,并使用t函数检查第一个点是否在三角形中。

t使用重心方法来确定是否UABC:(XYXto Y向量写),因为它(AB,AC)是平面的基础(A,B,C对齐的退化情况除外),AU可以写为AU = u.AB + v.ACU并在三角形iff中u > 0 && v > 0 && u+v < 1。例如,在这里查看更详细的解释和漂亮的交互式图表。注意:为了省几个字符,避免DIV0错误,我们只计算一个快捷方式u,并v和修改的测试(min(u*k,v*k,k-u-v)>0)。

使用的唯一算术运算符+-*min()>0

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.