分类四边形| 帮助我进行数学考试!


20

救命!我的数学考试即将上线,我没有学习!1考试的一部分是根据给定的顶点坐标对四边形进行分类,但不幸的是,我不知道该怎么做。2

因此,您面临的挑战是编写一个程序来为我执行此操作,这样我就不会失败!

挑战

给定四个顶点(其中三个顶点都不共线),确定由这四个顶点形成的四边形的最具体分类。

我所说的“最具体的分类”是即使所有正方形都是矩形,但如果形状是正方形,则应指出它是正方形而不是长方形。

输入值

输入将以四个(x,y)坐标给出。您可以将它们作为长度为4的列表/长度为2的元组的列表。或者,也可以将输入作为x坐标的列表和各个y坐标的列表。

例如,如果我的形状具有点顶点(0, 0)(5, 0)(6, 1),和(1, 1),你可以选择采取输入任一下列格式或类似的东西:

[(0, 0), (5, 0), (6, 1), (1, 1)]
([0, 5, 6, 1], [0, 0, 1, 1])

您可以假设四边形不是自相交的,并且点以正确的顺序给出(即,输入中的两个连续点将由四边形中的线段连接)。

输出量

以下四边形的每一个类别都需要一个唯一的输出:

  • 广场
  • 长方形
  • 菱形
  • 平行四边形
  • 梯形/梯形
  • 风筝
  • 四边形

这可能是确切的名称本身,一个字符,一个整数等。

规则

  • 适用标准漏洞
  • 如果您的编程语言具有将执行此确切任务的内置程序,则不允许该内置程序。
  • 允许使用内置函数查找两点之间的距离。
  • 允许使用内置函数查找两条线之间的角度。

此时,如果您知道所有术语,就可以开始编程了!(测试用例在最后)

术语

本节适用于需要澄清不同形状定义的任何人。

广场

当且仅当四边形的所有边长相等且每对相邻边垂直(即,既是矩形又是菱形)时,四边形才是正方形。

长方形

当且仅当每对相邻边垂直时,四边形才是矩形。

菱形

当且仅当四边形的所有边均相等时,四边形才是菱形。

平行四边形

当且仅当每对相对的边平行且每对相对的角度相等时,四边形才是平行四边形。这两个条件相互暗示,因此您只需要检查其中之一即可。

梯形/梯形

当且仅当四边形具有至少一对平行边时,它才是梯形/梯形。

风筝

如果两对相对的相邻边的长度相等,则四边形为风筝。也就是说,它的两个相邻边相等,另外两个也相等。

测试用例

input as (x, y) * 4 -> full name
[(0, 0), (1, 0), (1, 1), (0, 1)] -> square
[(0, 0), (1, 1), (-1, 3), (-2, 2)] -> rectangle
[(0, 0), (5, 0), (8, 4), (3, 4)] -> rhombus
[(0, 0), (5, 0), (6, 1), (1, 1)] -> parallelogram
[(0, 0), (4, 0), (3, 1), (1, 1)] -> trapezoid/trapezium
[(0, 0), (1, 1), (0, 3), (-1, 1)] -> kite  
[(0, 0), (2, 0), (4, 4), (0, 1)] -> quadrilateral

链接(Desmos图形计算器)

这里是每个测试用例的可视化链接。

正方形
矩形
菱形
平行四边形
梯形/梯形
风筝
四边形

获奖标准

我显然不能带计算机参加考试,因此我需要您编写尽可能短的代码,以便我能够记住。我需要将其写入空白处并使用TryItOffline TM运行它,以便使其适合空白处,您的程序需要尽可能小!

1当然我实际上是:P
2当然我实际上是:P


1
我也许可以为您解决保证金问题xkcd.com/1381
Rohan Jhunjhunwala

@RohanJhunjhunwala我是新的费马(我认为这是合适的人吗?)。但不错的XKCD ref:P
HyperNeutrino

可以输入CSV吗?
tuskiomi

特异性的部分顺序是什么?
彼得·泰勒

Answers:


6

APL(Dyalog)104 89 80 82 81 79 78字节

⍙←{⍵⍺⍺1⌽⍵}
⎕←(|x){⍵≡2⌽⍵:≡⍙¨0⍺⍵⋄2 4=+/1=2|+⍙↑⍵(=⍙⍺)}2|1+-⍙(12x←-⍙⎕+.×1 0J1)÷○1

在线尝试!


输入输出

取一个4×2的坐标矩阵作为输入

产出

  • 1 1 1 对于广场
  • 1 1 0 菱形
  • 1 0 1 矩形
  • 1 0 0 对于平行四边形
  • 1 0 风筝
  • 0 1 用于梯形
  • 0 0 对于四边形

算法

首先,找到四边形的所有4个边长和角度

如果两对相反的角度都相等(OA),则形状为某种平行四边形。确定所有边长是否相等(AS,相邻边)以及所有角度是否相等(AA)。

+--------+----------------+----------------+
|        |       AA       |      ~AA       |
+--------+----------------+----------------+
|   AS   |     Square     |    Rhombus     |
|--------+----------------+----------------+
|  ~AS   |    Rectangle   |  Parallelogram |
+--------+----------------+----------------+

如果不是OA,则:

  • 确定是否正好有两对相等的相邻边,以及它们是否分开(aabb而不是aaab)。如果是这样,则形状为风筝。

  • 确定是否正好有一对平行的相对侧。如果是这样,则形状为梯形。

  • 否则,形状为四边形。


⍙←{⍵⍺⍺1⌽⍵}定义一个新的运算符。在APL中,运算符表示高阶函数。该运算符使用1个函数参数(⍺⍺),并返回一个单子函数,该函数为:

  1. 旋转(1⌽)参数(
  2. ⍺⍺在它和之间应用

这对于标量函数特别有用,因为大多数标量函数都隐式地跨数组参数映射,从而允许在环绕的每个相邻元素对之间应用这些参数。例如+⍙1 2 3 41 2 3 4 + 2 3 4 1将计算得到3 5 7 5


x←-⍙⎕+.×1 0J1 将输入坐标矩阵转换为表示该形状的4个边的向量的复数数组。

  • ,当被引用时,获取并返回输入

  • 1 0J1代表向量[1,i](在数学意义上为“向量”,而“ i”为-1的平方根)。在APL中,a+bi写入复数aJb

  • +.×矩阵乘法。在数学上,结果将是4×1矩阵。但是,+.×在APL中被称为“内积”,它概括了矩阵乘法和矢量内积,并允许您甚至将3维数组与2维数组相乘。在这种情况下,我们将4×2矩阵和2元素向量相乘,得到4元素向量(具有4个给定顶点的复数表示)。

  • -⍙如上所述,是成对减法并带有环绕。这给出了形状的4个边的向量(以复数表示)。这些向量指向“反向”方向,但这无关紧要。

  • x← 将其存储到变量中 x


2|1+-⍙(12○x)÷○1 找到(表示)形状的4个顶点处的外角。

  • 12○x找到主要论点 4个侧面向量中每一个(以弧度表示)。

  • ÷○1除以π,以便更轻松地处理角度。因此,所有角度均表示为直角的倍数。

  • -⍙如上所述成对减法并带有环绕。这给出了4个外角。

  • 2|1+ 主要参数的上限为(-1,1],而成对减法则使范围为(-2,2]。这很糟糕,因为相同的角度具有2种不同的表示形式。通过执行“ add 1 mod 2”,角度可以重新上限为(0,2]。尽管所有角度都比应有的角度大1,但记住这一点也很好。


|x发现大小各4个侧向量的


{⍵≡2⌽⍵:≡⍙¨0⍺⍵⋄2 4=+/1=2|+⍙↑⍵(=⍙⍺)}定义并应用一个函数,该函数以4个外角的数组为右引数,以4个边长的数组为右引数

  • 该函数具有受保护的表达式。在这种情况下,⍵≡2⌽⍵就是警卫。
  • 如果警卫队求值为,1则执行下一个表达式≡⍙¨0⍺⍵并返回其值。
  • 如果警卫队求值为0,则跳过该表达式,然后2 4=...=⍙⍺)执行该表达式。

⍵≡2⌽⍵ 检查两对相反的角度是否相等。

  • 2⌽⍵ 将角度数组旋转2个位置。
  • ⍵≡检查是否与自身相同

≡⍙¨0⍺⍵ 返回每个平行四边形类型形状的唯一值。

  • 0⍺⍵是标量的3元素数组0,边长数组和angles数组
  • ≡⍙¨ 执行 ≡⍙为每个元素。
  • ≡⍙通过检查数组的所有值是否相等来检查数组的所有值是否相等。标量不旋转,因此≡⍙0返回1。如上所述,≡⍙⍺检查菱形并≡⍙⍵检查矩形。

2 4=+/1=2|+⍙↑⍵(=⍙⍺)为每个非平行四边形类型的形状返回唯一值。这是通过缠绕风筝和梯形的支线来实现的。


2=+/1=2|+⍙⍵ 检查梯形。

  • +⍙⍵给出相邻的角度和。平行线的内角总和为直角,因此四边形的平行边的外角也是如此。因此,每对平行边应导致两个1-1相邻的角度之和。

  • 1=2|但是,in 中的角度比应有的角度大1,因此角度实际上加起来为13。可以通过“ mod 2等于1”来检查。

  • +/对数组求和。得出相邻角度和的计数为13

  • 2= 检查是否等于2。(即,是否有一对平行的边)


4=+/1=2|+⍙(=⍙⍺) 检查风筝。

  • (=⍙⍺)给出一个数组,该数组指示哪些相邻边相等。不像,是=逐个元素地工作。因此,这是一个带有1s 的4元素数组,其中该边的长度等于“下一个”边的长度。

  • +⍙ 成对加总和。

  • 1=2|由于(=⍙⍺)给出了一个布尔阵列(一个只用0S和1S)的成对之和的唯一可能的值是012。所以1=2|就和1=

  • +/对数组求和。这给出了成对和的计数1

  • 4=检查是否等于4。唯一的发生方式是if (=⍙⍺)1 0 1 00 1 0 1。如上所述,这意味着形状是风筝。


2 4=+/1=2|+⍙↑⍵(=⍙⍺) 将上述检查交织在一起。

  • ⍵(=⍙⍺)是数组和数组的2元素嵌套数组(=⍙⍺)

  • 将嵌套数组提升为适当的矩阵。由于⍵(=⍙⍺)是4元素数组的2元素数组,因此结果是2×4矩阵。

  • +⍙由于(并通过扩展)将最后一个(水平)轴旋转+⍙到矩阵,因此与分别应用于+⍙每一行的矩阵相同。

  • 1=2|残差/ mod(|)和equals(=)均基于每个元素工作,甚至适用于矩阵。

  • +/默认情况下,reduce(/)沿最后一个(水平)轴工作。因此,+/沿着行求和,然后将2×4矩阵变成2元素的简单数组。

  • 2 4=由于=每件作品,这同时检查风筝和梯形条件。


3

Mathematica,195个字节

Which[s=Differences@{##,#};l=Norm/@s;r=#.#2==#2.#3==0&@@s;Equal@@l,If[r,1,2],#==#3&&#2==#4&@@l,If[r,3,4],MatchQ[l,{a_,b_,b_,a_}|{a_,a_,b_,b_}],5,#+#3=={0,0}||#2+#4=={0,0}&@@Normalize/@s,6,1>0,7]&

带空格:

Which[
    s = Differences @ {##,#};
    l = Norm /@ s;
    r = #.#2 == #2.#3 == 0& @@ s;

    Equal @@ l, If[r, 1, 2],
    # == #3 && #2 == #4& @@ l, If[r, 3, 4],
    MatchQ[l, {a_,b_,b_,a_}|{a_,a_,b_,b_}], 5,
    #+#3 == {0,0} || #2+#4 == {0,0}& @@ Normalize /@ s, 6,
    1 > 0, 7
]&

输出1为正方形,2为菱形,3为矩形,4为平行四边形,5风筝,6为梯形,并7为别的。我发布了一个TIO链接,但这显然在Mathics中不起作用。

如果这四个点是PQR,和S,然后{##,#}{P,Q,R,S,P},所以s是侧向量列表{Q-P,R-Q,S-R,P-S}l是这些矢量的长度,并且r是条件之间的角度Q-PR-Q以及之间的角度R-QS-R均为90摄氏度。

因此,如果所有边长均相等,则四边形为菱形。如果r成立,它实际上是一个正方形,否则它只是一个普通的菱形。

排除菱形,如果两对相对的边长相等,则四边形仍为平行四边形。如果r成立,则实际上是一个矩形,否则,它只是一个普通的平行四边形。

排除了平行四边形,边长的列表l的形式为{a,b,b,a}{a,a,b,b}对于一些ab,则四边形为风筝。请注意,它不能另外是梯形,或者实际上是菱形。

排除平行四边形和风筝,如果四边形具有一对平行边,则它是梯形。我们通过检查Normalize边向量并检查是否有一对相反的向量添加来{0,0}

排除以上所有情况1 > 0(如果更好),则四边形只是普通的旧四边形。


1

Python 2中463个 410 408 397字节

通过在第六行使用元组而不是索引到列表,节省了53个字节。

通过移至输出整数1至7而不是每种形状的首字母来节省11个字节。整数对应如下:

  1. 广场
  2. 长方形
  3. 菱形
  4. 平行四边形
  5. 梯形
  6. 风筝
  7. 四边形
from numpy import *;D=dot
from numpy.linalg import *;N=norm
def P(a,b):x=D(a,b);y=N(a)*N(b);return x==y or x==-y
def Q(a,b):return int(N(a)==N(b))
L=input()
a,b,c,d=tuple([(L[i][0]-L[(i+1)%4][0],L[i][1]-L[(i+1)%4][1]) for i in range(4)])
g=7
e=Q(a,c)+Q(b,d)
if e==2:
 g=(1if D(a,b)==0 else 3) if Q(a,b) else 2 if D(a,b)==0 else 4
elif P(a,c) or P(b,d):
 g = 5
elif Q(a,b) or Q(b,c):
 g = 6
print g

在线尝试!

展现逻辑

显示为功能,以显示不同测试输入的输出。请注意,我从问题中最初提供的示例(不是矩形)中更改了“矩形”测试示例。

逻辑取决于点积和四边形边形成的向量的范数(长度),以评估边的长度是否相等,相对边平行还是垂直于相邻边。

def S(va, vb):
    return (va[0]-vb[0], va[1]-vb[1])
def dot(sa,sb):      # Eventually replaced with numpy.dot
    return(sa[0]*sb[0]+sa[1]*sb[1])
def norm(s):         # Eventually replaced by numpy.linalg.norm
    return (s[0]**2+s[1]**2)**.5
def isperp(a,b):     # Test if lines/vectors are perpendicular
    return dot(a,b)==0
def ispar(a,b):      # Test if lines/vectors are parallel
    x = dot(a,b)
    y = norm(a)*norm(b)
    return x == y or x == -y
def iseq(a,b):       # Test if lines/vectors are equal in length
    return norm(a)==norm(b)
   
def f(L):
    #Define the four sides
    s = []
    for i in range(4):
        s.append(S(L[i],L[(i+1)%4]))  # I refer often so shorter names may eventually

    guess = 'Q'
    eqsides = 0           # These 6 lines eventually golfed using integer arithmetic by returning an int from iseq()
    if iseq(s[0], s[2]):
        eqsides += 1
    if iseq(s[1],s[3]):
        eqsides += 1
    if eqsides == 2:
    # Opposite sides are equal, so square, rhombus, rectangle or parallelogram
        if iseq(s[0],s[1]):       #Equal adjacent sides, so square or rhombus
            guess='S' if isperp(s[0], s[1]) else 'H'
        else:                     # rectangle or Parallelogram
            guess='R' if isperp(s[0], s[1]) else 'P'
    elif ispar(s[0],s[2]) or ispar(s[1],s[3]):
        guess = 'T'
    elif iseq(s[0],s[1]) or iseq(s[1],s[2]):
        guess = 'K'
    return guess
    

#test suite:
print f([(0, 0), (1, 0), (1, 1), (0, 1)]) # -> square
print f([(0, 0), (1, 1), (-1, 3), (-2, 2)]) # -> rectangle
print f([(0, 0), (5, 0), (8, 4), (3, 4)]) #  -> rhombus
print f([(0, 0), (5, 0), (6, 1), (1, 1)]) #  -> parallelogram
print f([(0, 0), (4, 0), (3, 1), (1, 1)]) # -> trapezoid/trapezium
print f([(0, 0), (1, 1), (0, 3), (-1, 1)]) #-> kite  
print f([(0, 0), (2, 0), (4, 4), (0, 1)]) #-> quadrilateral

在线尝试!


1
错误[(0, 0), (2, 2), (4, 0), (0,-2)]归类为风筝
TwiNight

这行得通吗?repl.it/JRzE
扎卡里

@TwiNight谢谢。没有看到这种可能性。问题是我的初始算法仅检查是否有一对长度匹配的边。如您的示例所示,这还不够。我需要检查一对匹配的边,然后检查相对的一对长度是否也相似。太忙了,无法实现。
CCB60

0

批次,287个字节

@set/aa=%3-%1,b=%4-%2,c=%5-%1,d=%6-%2,e=%7-%1,f=%8-%2,g=a*a+b*b,h=(h=c-a)*h+(h=d-b)*h,i=(i=c-e)*i+(i=d-f)*i,j=e*e+f*f,p=!(i-g)+!(j-h),q=!(h-g),r=!(a*e+b*f),k=q+!(j-i)^|!(j-g)+!(h-i),t=!(a*(f-d)-b*(e-c))+!((c-a)*f-(d-b)*e)
@if %p%==2 (echo 1%r%%q%)else if %k%==2 (echo 1)else (echo 1%t%)

输出为二进制:1=风筝,10=四边形,11=梯形,100=平行四边形,101=菱形,110=矩形,111=正方形。说明:g, h, i, j是边长的平方。p是具有相同长度的相对边的对数,q通过检查相对的对实际上是否相等r来区分平行四边形/矩形和菱形/正方形,通过垂直度检查来区分平行四边形/菱形和矩形/正方形,k检查通过寻找成对的相等的相邻侧面来放风筝,并t通过几个平行的侧面检查来检查梯形。



@TwiNight Bah,检查风筝确实很尴尬。
尼尔

是的,我很幸运找到一种紧凑的方式来做
TwiNight

@TwiNight,我会相信你的;我完全不了解APL。
尼尔

我检查风筝的部分是2=|-.=⍙⍺。如果您忽略计算中的工作(4个边的长度)和要定义的整行,肯定看起来很紧凑
TwiNight
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.