最小的整数磁盘


23

挑战在于找到包含某些给定点的最小磁盘。但是,由于在这一挑战中磁盘的坐标和半径都必须都是整数,这一点变得有些棘手。

您的输入将是具有整数坐标x和的点的列表y。您可以将其作为元组列表,列表列表或任何其他表示对集合的方式。x并且y都是(可能是负数)整数。每个点都保证是唯一的,并且至少会有一个点。

你的输出将在3号,形式的磁盘XYRXYR都是整数,X并且Y代表了磁盘的中心,R代表它的半径。每个给定点与中心之间的距离必须小于或等于R,并且必须不存在这样的较小的磁盘,该磁盘R也要满足此条件。

对于给定的输入,可能会有多种解决方案,在这种情况下,您的代码必须至少输出其中一种。

您可以使用语言支持的任何种类的几何内置函数(如果有),并且输入/输出可以通过内置的点/磁盘对象而不是数字来实现。

测试用例

Input   (Possible) Output(s)
(x,y)   (X,Y,R)
-------------------------
(0,0)   (0,0,0)
-------------------------
(0,1)   (0,0,1)
(1,0)   (1,1,1)
-------------------------
(1,4)   (4,4,3)
(3,2)
(4,1)
(4,5)
(5,2)
(7,4)
-------------------------
(-1,0)  (0,0,2)
(2,0)   (1,0,2)
-------------------------
(-1,0)  (1,0,2)
(2,1)   (0,1,2)
-------------------------
(0,0)   (1,0,1)
(1,1)   (0,1,1)

最少的字节数获胜。



发现一对夫妇错别字,如果你不介意我指点出来:“这在一定程度上做出欺骗呃......”; “...表示盘的中心和R表示我小号半径...”; “ ...而且一定不存在这样的磁盘...”
J.Sallé18年

2
通常,使事物变为整数只会使代码高尔夫更容易。
user202729

@KevinCruijssen碰巧。输入可以是任何顺序。
帕维尔

1
@Pavel输入可以是任何顺序,还是我们可以以任何顺序输入?就像输入一样,输入可以是任何顺序,我们应该在解决方案中先进行手动排序,还是可以对输入进行预先排序?
凯文·克鲁伊森

Answers:


6

果冻25 24 22 21 20 18字节

«/r»/Œpµ³_²§½ṀĊ,)Ṃ

感谢@EriktheOutgolfer让我知道了),节省了1个字节。

感谢@Dennis节省了2个字节。

在线尝试!

说明

«/r»/Œpµ³_²§½ṀĊ,)Ṃ      Main link. Arg: points
                        e.g. [[1,4],[3,2],[3,1]]
«/                      Find minimums by coordinate
                        e.g. [1,1]
   »/                   Find maximums by coordinate
                        e.g. [3,4]
  r                     Inclusive ranges by coordinate
                        e.g. [[1,2,3],[1,2,3,4]]
     Œp                 Cartesian product of the x and y ranges
                        e.g. [[1,1],[1,2],[1,3],[1,4],...,[3,4]]
       µ                    Chain, arg: center
                            e.g. [1,3]
        ³                   Get the original points
                            e.g. [[1,4],[3,2],[3,1]]
         _                  Subtract the center from each
                            e.g. [[0,1],[2,-1],[2,-2]]
          ²                 Square each number
                            e.g. [[0,1],[4,1],[4,4]]
           §                Sum each sublist
                            e.g. [1,5,8]
            ½               Square root of each number
                            e.g. [1,2.24,2.83]
             Ṁ              Find the maximum
                            e.g. 2.83
              Ċ             Round up
                            e.g. 3
               ,            Pair with the center point
                            e.g. [3,[1,3]]
                )       Do the above for all points
                        e.g. [[3,[1,1]],[3,[1,2]],[3,[1,3]],...,[3,[3,4]]]
                 Ṃ      Find the lexicographically smallest pair
                        e.g. [3,[1,1]]

@丹尼斯谢谢!自从Jelly的向量化何时重复较短的列表,还是我误解了删除
PurkkaKoodari

深度首先匹配。如果您有一对和成对的阵列,则该对将与所有对配对。
丹尼斯

8

Brachylog v2,19个字节

;Az{\-ᵐ~√ᵐ+}ᵐ≤ᵛ√;A≜

在线尝试!

这个程序很容易编写-Brachylog对于这种问题几乎是完美的-但很难打高尔夫。如果在这里的某个地方节省了字节,这不会令我感到惊讶,因为我所做的几乎没有什么作用(而且它包含嵌套的映射指令,通常是您应该使用member / findall的标志,但是我不能看到一种方法)。

这是函数提交。输入是从左参数到格式的函数,[[x,y],[x,y],…]从右参数以格式的输出[r,[[x,y]]]。(如果要在输入中尝试负数,请注意,Brachylog使用_负号,而不是负号-。这令人困惑,因为Brachylog附带的功能→完整程序包装器(使用命令行参数请求)Z将显示负数。在输出中带有常规减号。)

说明

;Az{\-ᵐ~√ᵐ+}ᵐ≤ᵛ√;A≜
;A                   Append something
  z                    to every element of the input
   {       }ᵐ        such that for each resulting element:
     -                 Subtracting
    \ ᵐ                  corresponding elements {of the (input, appended) element}
       ~√              and un-squarerooting
         ᵐ               {the result of} each {subtraction}
          +            and summing {the resulting square numbers}
             ≤       {lets us find} a number at least as large as
              ᵛ        every element {of the list of sums}
               √     which can be square-rooted;
                ;A   append the same list as initially to it.
                  ≜  Find the first integer solution to the above, lexicographically.

有趣的是,我们要求Brachylog查找某些属性的值(在这种情况下,磁盘的半径以A适合所有输入点的点为中心),但是几乎没有任何要求(我们需要的是半径是一个数字)。但是,Brachylog会在内部以符号方式计算所讨论的半径,而不是尝试使用具体数字,因此,在到达最终状态时,它会立即完成两件事:首先,确保仅将整数用于A半径的坐标和半径(强制平方半径为平方数,并说明如何使用“ ≤ᵛ找到最大或更大”);其次,找到可行的最小半径(因为半径在输出中排在第一位)。

程序中完全没有指定的一件事是,所有点都是相对于磁盘的同一中心测量的;按照书面规定,没有限制,我们不会对每个点使用不同的中心。但是,平局决胜顺序(在这种情况下由第三个决定,并且作为结构约束将在隐含的值约束之前进行评估)要A尽可能短(即单个元素,因此我们使用相同的每次居中;它先尝试零长度,A但显然不起作用,因此接下来尝试单例列表)。结果,我们最终得到了一个有用的约束(即我们只有一个磁盘)“免费”。

该解决方案可以推广到任意数量的维度,而无需更改源代码。这里没有假设事物是二维的。因此,如果您恰巧需要最小的整数球体,也可以这样做。


3

Perl 6,81个字节

{min [X]([Z]($^p)>>.minmax).map:{$p.map({(@_ Z-$_)>>².sum**.5}).max.ceiling,$_}}

在线尝试!

将点列表作为2元素列表((X1, Y1), (X2, Y2), ...)。返回一个列表(R, (X, Y))。使用与Pietu1998的Jelly答案相同的方法:

[X]([Z]($^p)>>.minmax)  # All possible centers within the bounding box
.map:{ ... }            # mapped to
$p.map({(@_ Z-$_)>>².sum**.5}).max  # maximum distance from any point
.ceiling                # rounded up,
,$_                     # paired with center.
min                     # Find minimum by distance.

minmax方法在这里很有用,因为它返回一个Range。范围的笛卡尔积直接产生具有整数坐标的所有点。


2

05AB1E,26 个字节

øεWsàŸ}`âεUIεX-nOt}àîX‚}{н

@ Pietu1998的Jelly答案端口。

在线尝试验证所有测试用例

说明:

ø                    # Zip the (implicit) input, swapping the rows and column
                     #  i.e. [[1,4],[3,2],[3,1]] → [[1,3,3],[4,2,1]]
 ε    }              # Map each to:
  W                  #  Push the smallest value (without popping the list)
                     #   i.e. [[1,3,3],[4,2,1]] → [1,1]
   s                 #  Swap so the list is at the top of the stack again
    à                #  Pop the list and push the largest value
                     #   i.e. [[1,3,3],[4,2,1]] → [3,4]
     Ÿ               #  Take the inclusive range of the min and max
                     #   i.e. [[1,2,3],[1,2,3,4]]
`                    # After the map, push both lists separated to the stack
 â                   # And take the cartesian product of the two lists
                     #  i.e. [[1,2,3],[1,2,3,4]]
                     #   → [[1,1],[1,2],[1,3],[1,4],[2,1],[2,2],[2,3],[2,4],[3,1],[3,2],[3,3],[3,4]]
  ε             }    # Map each pair to:
   U                 #  Pop and store the current value in variable `X`
    I                #  Push the input
     ε     }         #  Map each pair in the input to:
      X              #   Push variable `X`
       -             #   Subtract it from the current pair
                     #    i.e. [3,2] - [1,3] → [2,-1]
        n            #   Take the square of each
                     #    i.e. [2,-1] → [4,1]
         O           #   Sum the lists
                     #    i.e. [4,1] → 5
          t          #   Take the square-root of each
                     #    i.e. 5 → 2.23606797749979
            à        #  Pop the converted list, and push its largest value
                     #   i.e. [[3.0,2.23606797749979,2.0],[2.0,2.0,2.23606797749979],...,[2.0,2.0,3.0]]
                     #    → [3.0,2.23606797749979,...,3.0]
             î       #  Round it up
                     #   i.e. [3.0,2.23606797749979,...,3.0] → [3.0,3.0,3.0,4.0,4.0,3.0,3.0,4.0,4.0,3.0,3.0,3.0]
              X     #  Pair it with variable `X`
                     #   i.e. [[3.0,[1,1]],[3.0,[1,2]],...,[3.0,[3,4]]]
                 {   # After the map, sort the list
                  н  # And take the first item (which is output implicitly)
                     #  i.e. [[3.0,[1,1]],[3.0,[1,2]],...,[3.0,[3,4]]] → [3.0,[1,1]]

2

Matlab,73个字节

function g(x);[r,~,d]=fminimax(@(a)pdist2(x,a),[0 0]);[round(r) ceil(d)]

只需找到最小的解(浮点)并四舍五入到最接近的点并确定半径(最小极大问题的最坏情况)。我不确定这是否能为所有可能的情况(在精度范围内)提供正确的解决方案,但是对于测试用例,它应该可以工作(如果我没有输入错误)。

叫它

g([1 4;3 2;4 1;4 5;5 2;7 4])

(0,0),(1,1)fminimax(0.5,0.5)(1,1)2/21(0,0)

您是正确的,但fminimax的输出为[0.500000211699422 0.499999788525202],因此正确舍入。所以我很幸运。我目前正在考虑如何回避这个问题(因为它只能靠运气了)。
乔纳斯(Jonas)

2

Pyth34 33字节

hSm+.EeSm@s^R2-Vdk2Qd*Fm}FhM_BSdC

输出形式为 [R,x,y]

在此处在线尝试,或在此处一次验证所有测试用例。

hSm+.EeSm@s^R2-Vdk2Qd*Fm}FhM_BSdCQ   Implicit: Q=eval(input())
                                     Trailing Q inferred
                                CQ   Transpose (group x and y coordinates separately)
                       m             Map each in the above, as d, using:
                              Sd       Sort d
                            _B         Pair with its own reverse
                          hM           Take the first element of each, yielding [min, max]
                        }F             Generate inclusive range
                     *F              Cartesian product of the above two lists, yielding all coordinates in range
  m                                  Map each coordinate in the above, as d, using:
        m          Q                   Map each coordinate in input, as k, using:
              -Vdk                       Take the difference between x and y coordinates in d and k
           ^R2                           Square each
          s                              Sum
         @        2                      Take the square root
      eS                               Take the largest of the result
    .E                                 Rounded up
   +                d                  Prepend to d
 S                                   Sort the result, first element as most significant
h                                    Take first element

编辑:通过重新排列输出格式保存了一个字节,以前的版本:

heDm+d.EeSm@s^R2-Vdk2Q*Fm}FhM_BSdC


2

Wolfram语言(Mathematica),66字节

这是一种蛮力方法。我考虑了更短的BoundingRegion[#,"MinDisk"]&函数,但是没有办法强制使用整数坐标和半径。

Minimize[{r,RegionWithin[{x,y}~Disk~r,Point@#]},{x,y,r},Integers]&

在线尝试!


真好 但是,怎么样{Round@#[[1]], Ceiling@#[[2]]} &@BoundingRegion[#, "MinDisk"]&
DavidC

@DavidC,中心的圆角可能会将其向上移动至Sqrt [2] /2=.707,但采用天花板不一定会为半径增加足够的长度来抵消该误差。我认为失败的一个例子就是两点{{0,0},{11,11}}
Kelly Lowder

我明白你的意思了!
DavidC

2

Java的10,283个 279 277 257字节

C->{int M=1<<31,m=M,X=M,Y=M,x=M-1,y=x,t,a,b,r[]={x};for(var c:C){x=(t=c[0])<x?t:x;X=t>X?t:X;y=(t=c[1])<y?t:y;Y=t>Y?t:Y;}for(;y<=Y;y++)for(t=x;t<=X;r=m<r[0]?new int[]{m,t,y}:r,m=M,t++)for(var c:C){a=c[0]-t;b=c[1]-y;a*=a;m=(a=(int)Math.ceil(Math.sqrt(a+=b*=b)))>m?a:m;}return r;}

@nwellnhof的使用技巧,-20个字节Math.hypot

结果数组的顺序为[R,X,Y]

在线尝试。

说明:

C->{                  // Method with 2D int-array as parameter & int-array as return-type
  int M=1<<31,        //  Minimum `M`, starting at -2,147,483,648
      m=M,            //  Temp integer, starting at -2,147,483,648 as well
      X=M,            //  Largest X coordinate, starting at -2,147,483,648 as well
      Y=M,            //  Largest Y coordinate, starting at -2,147,483,648 as well
      x=M-1,          //  Smallest X coordinate, starting at 2,147,483,647
      y=x,            //  Smallest Y coordinate, starting at 2,147,483,647 as well
      t,a,            //  Temp integers, starting uninitialized
      r[]={x};        //  Result-array, starting at one 2,147,483,647
  for(var c:C){       //  Loop over the input-coordinates
    x=(t=c[0])<x?t:x; //   If the X coordinate is smaller than `x`, change it
    X=t>X?t:X;        //   If the X coordinate is larger than `X`, change it
    y=(t=c[1])<y?t:y; //   If the Y coordinate is smaller than `y`, change it
    Y=t>Y?t:Y;}       //   If the Y coordinate is larger than `Y`, change it
 for(;y<=Y;y++)       //  Loop `y` in the range [`y`,`Y`]:
   for(t=x;t<=X       //   Inner loop `t` in the range [`x`,`X`]:
          ;           //     After every iteration:
           r=m<r[0]?  //      If `m` is smaller than the first value:
              new int[]{m,t,y}
                      //       Replace the result with `m,t,y`
             :        //      Else:
              r,      //       Leave `r` unchanged
           m=M,       //      Reset `m` to -2,147,483,648 for the next iteration
           t++)       //      And increase `t` by 1
     for(var c:C)     //    Inner loop over the input-coordinates
       m=(a=(int)Math.ceil(Math.hypot(c[0]-t,c[1]-y)))
                      //     Subtract `t` from the X coordinate;
                      //     subtract `y` from the Y coordinate;
                      //     take the hypot (<- sqrt(x*x+y*y)) of those
                      //     ceil it
                      //     And set `a` to this value
          >m?         //     If `a` is larger than `m`:
           a          //      Set `m` to `a`
          :           //     Else:
           m;         //      Leave `m` unchanged
  return r;}          //  Return the result `r`

1
您可以使用保存至少8个字节Math.hypot
nwellnhof

@nwellnhof啊,完全忘了Math.hypot,这对这个挑战来说是完美的!-20个字节。谢谢。:)
Kevin Cruijssen

1

Javascript,245个字节

a=>{[b,c,d,e]=a.reduce(([j,k,l,m],[h,i])=>[j>h?j:h,k<h?k:h,l>i?l:i,m<i?m:i],[,,,,]);for(f=c;f<b;f++){for(g=e;g<d;g++){s=a.reduce((o,[p,q])=>o>(r=(p-f)**2+(q-g)**2)?o:r);n=n?n[2]>s?[f,g,s]:n:[f,g,s]}}return [n[0],n[1],Math.ceil(Math.sqrt(n[2]))]}

(有点)更具可读性的版本:

a=>{
    [b,c,d,e]=a.reduce(([j,k,l,m],[h,i])=>[j>h?j:h,k<h?k:h,l>i?l:i,m<i?m:i],[,,,,]);
    for(f=c;f<b;f++){
        for(g=e;g<d;g++){
            s=a.reduce((o,[p,q])=>o>(r=(p-f)**2+(q-g)**2)?o:r);
            n=n?n[2]>s?[f,g,s]:n:[f,g,s]
        }
    }
    return [n[0],n[1],Math.ceil(Math.sqrt(n[2]))]
}

只需找到边界框,然后测试该框中的每个坐标是否最佳即可。

我可以通过替换以下内容来节省8个字节:

Math.ceil(Math.sqrt(n[2]))~~(n[2]+1-1e-9)


当然,还有很多事情可以打高尔夫球,但是JS不是我的强项。不过,你可以打高尔夫球for(f=c;f<b;f++){for(g=e;g<d;g++){s=a.reduce((o,[p,q])=>o>(r=(p-f)**2+(q-g)**2)?o:r);n=n?n[2]>s?[f,g,s]:n:[f,g,s]}}for(f=c;f<b;f++)for(g=e;g<d;n=n?n[2]>s?[f,g,s]:n:[f,g,s],g++)s=a.reduce((o,[p,q])=>o>(r=(p-f)**2+(q-g)**2)?o:r);。而且我很确定您可以删除处的空格return[
凯文·克鲁伊森

1
您可能可以使用保存几个字节Math.hypot
nwellnhof


1

木炭,65字节

≔Eθ§ι¹ζ≔Eθ§ι⁰ηF…·⌊η⌈ηF…·⌊ζ⌈ζ⊞υ⟦ικ⟧≔Eυ⌈EθΣEιX⁻§λξν²ηI§υ⌕η⌊ηI⌈X⌊η·⁵

在线尝试!链接是详细版本的代码。说明:

≔Eθ§ι¹ζ

将y坐标输入z

≔Eθ§ι⁰η

将x坐标输入h

F…·⌊η⌈ηF…·⌊ζ⌈ζ⊞υ⟦ικ⟧

循环显示从最小到最大的包容范围,hz生成所有潜在光盘中心的列表。

≔Eυ⌈EθΣEιX⁻§λξν²η

遍历所有圆盘中心,然后遍历所有原始点,然后遍历两个坐标,减去,平方,求和,取最大值,并保存结果列表。

I§υ⌕η⌊η

找到最小最大直径的位置,然后打印相应的光盘中心。

I⌈X⌊η·⁵

打印最小的最大直径,但将其四舍五入到下一个整数。

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.