Golf vòng tròn nhỏ nhất!


29

Vấn đề:

Cho một tập hợp các điểm không trống trong mặt phẳng Cartesian, tìm vòng tròn nhỏ nhất bao quanh tất cả chúng ( liên kết Wikipedia ).

Vấn đề này không đáng kể nếu số điểm bằng ba hoặc ít hơn (nếu có một điểm, đường tròn có bán kính bằng 0; nếu có hai điểm, đoạn thẳng nối các điểm là đường kính của đường tròn; nếu có ba điểm (không phải colinear), có thể lấy phương trình của một đường tròn chạm vào tất cả chúng nếu chúng tạo thành một tam giác không bị che khuất hoặc một vòng tròn chỉ chạm vào hai điểm và bao quanh điểm thứ ba nếu tam giác bị che khuất). Vì vậy, vì lợi ích của thử thách này, số điểm phải lớn hơn ba.

Các thách thức:

  • Đầu vào: Một danh sách gồm 4 điểm không trở lên. Các điểm nên có tọa độ X và Y; tọa độ có thể là phao. Để giảm bớt thử thách, không có hai điểm nào có chung tọa độ X.
    Ví dụ:[(0,0), (2,1), (5,3), (-1,-1)]
  • Đầu ra: Một bộ giá trị, (h,k,r)sao cho là phương trình của đường tròn nhỏ nhất bao quanh tất cả các điểm.(xh)2+(yk)2=r2

Quy tắc:

  • Bạn có thể chọn bất cứ phương thức nhập nào phù hợp với chương trình của bạn.
  • Đầu ra nên được in STDOUThoặc trả về bởi một chức năng.
  • "Bình thường", mục đích chung, ngôn ngữ được ưa thích, nhưng bất kỳ esolang nào cũng được chấp nhận.
  • Bạn có thể giả định rằng các điểm không phải là màu.
  • Đây là môn đánh gôn, vì vậy chương trình nhỏ nhất tính bằng byte sẽ thắng. Người chiến thắng sẽ được chọn một tuần sau khi thử thách được đăng.
    • Vui lòng bao gồm ngôn ngữ bạn đã sử dụng và độ dài tính bằng byte làm tiêu đề trong dòng đầu tiên của câu trả lời của bạn: # Language: n bytes

Các trường hợp thử nghiệm:

  • 1:
    • Đầu vào: [(-8,0), (3,1), (-6.2,-8), (3,9.5)]
    • Đầu ra: [-1.6, 0.75, 9.89]
  • 2:
    • Đầu vào: [(7.1,-6.9), (-7,-9), (5,10), (-9.5,-8)]
    • Đầu ra: [-1.73, 0.58, 11.58]
  • 3:
    • Đầu vào: [(0,0), (1,2), (3,-4), (4,-5), (10,-10)]
    • Đầu ra: [5.5, -4, 7.5]
  • 4:
    • Đầu vào: [(6,6), (-6,7), (-7,-6), (6,-8)]
    • Đầu ra: [0, -0.5, 9.60]

Chúc bạn chơi golf vui vẻ !!!


Thử thách liên quan:



8
Nếu có ba điểm (không cùng tuyến tính), bạn có thể nhận được phương trình của một đường tròn chạm vào tất cả các đường thẳng đó có thể không phải là đường tròn bao quanh nhỏ nhất. Đối với ba đỉnh của một tam giác tù, đường tròn bao quanh nhỏ nhất là đường tròn có đường kính là cạnh dài nhất.
Anders Kaseorg

2
@Arnauld Giống như bạn. Đối với trường hợp thử nghiệm 2, tôi lấy trung tâm (-1,73, 0,58) và đối với trường hợp thử nghiệm 3 (5,5, -4).
Robin Ryder

@Arnauld cảm ơn bình luận của bạn. Tôi đã chỉnh sửa bài đăng phù hợp
Barranka

@Arnauld ôi, xin lỗi. Thật. Aldo, sửa chữa với những quan sát của bạn
Barranka

Câu trả lời:


26

Ngôn ngữ Wolfram (Mathicala) , 28 27 byte

#~BoundingRegion~"MinDisk"&

Hãy thử trực tuyến!

Được xây dựng là tiện dụng ở đây. Đầu ra là một đối tượng đĩa với tâm và bán kính. Giống như những người khác, tôi đã tìm thấy các trường hợp thử nghiệm thứ 2 và thứ 3 khác với câu hỏi.

Cảm ơn @lirtosiast vì đã tiết kiệm một byte!

Nếu một danh sách được yêu cầu là đầu ra, điều này có thể được thực hiện trong 35 byte (với chi phí thêm 8 byte) . Cảm ơn @Roman đã chỉ ra điều này.


3
Tôi đã mong đợi một Mathicala tích hợp. Nhưng tôi không mong đợi Mathicala có "đối tượng đĩa".
Robin Ryder

36 byte để có được định dạng đầu ra đúng:Append@@BoundingRegion[#,"MinDisk"]&
Roman

20

JavaScript (ES6),  298 ... 243  242 byte

Trả về một mảng [x, y, r].

p=>p.map(m=([c,C])=>p.map(([b,B])=>p.map(([a,A])=>p.some(([x,y])=>H(x-X,y-Y)>r,F=s=>Y=(d?((a*a+A*A-q)*j+(b*b+B*B-q)*k)/d:s)/2,d=c*(A-B)+a*(j=B-C)+b*(k=C-A),r=H(a-F(a+b),A-F(A+B,X=Y,j=c-b,k=a-c)))|r>m?0:o=[X,Y,m=r]),q=c*c+C*C),H=Math.hypot)&&o

Hãy thử trực tuyến!

hoặc xem phiên bản được định dạng

Làm sao?

phương pháp

Với mỗi cặp điểm , chúng ta tạo ra đường tròn có đường kính là .(A,B)(X,Y,r)AB

X=Ax+Bx2,Y=Ay+By2,r=(AxBx2)2+(AyBy2)2

Với mỗi bộ ba điểm riêng biệt , chúng ta tạo ra đường tròn bao quanh tam giác .(A,B,C)(X,Y,r)ABC

d=Ax(ByCy)+Bx(CyAy)+Cx(AyBy)
X=(Ax2+Ay2)(ByCy)+(Bx2+By2)(CyAy)+(Cx2+Cy2)(AyBy)2d
Y=(Ax2+Ay2)(CxBx)+(Bx2+By2)(AxCx)+(Cx2+Cy2)(BxAx)2d
r=(XAx)2+(YAy)2

Đối với mỗi vòng tròn được tạo, chúng tôi kiểm tra xem mỗi điểm có được bao quanh trong đó không:(x,y)

(xX)2+(yY)2r

Và cuối cùng chúng tôi trả lại vòng tròn hợp lệ nhỏ nhất.

Thực hiện

Trong mã JS, công thức tính toán cho vòng tròn được bao quanh của tam giác được đơn giản hóa một chút. Giả sử , chúng tôi xác định , dẫn đến:(X,Y)d0q=Cx2+Cy2

X=(Ax2+Ay2q)(ByCy)+(Bx2+By2q)(CyAy)2d
Y=(Ax2+Ay2q)(CxBx)+(Bx2+By2q)(AxCx)2d

Theo cách này, hàm trợ giúp chỉ cần hai tham số để tính toán từng tọa độ:F(j,k)

  • (ByCy,CyAy) choX
  • (CxBx,AxCx) choY

Tham số thứ ba được sử dụng trong (tức là tranh luận thực tế của nó ) được sử dụng để tính toán khi , có nghĩa là tam giác là thoái hóa và chúng ta phải cố gắng sử dụng kính để thay thế.Fs(X,Y)d=0


có lẽ viết một trình tối ưu hóa số kiểu Newton thì ngắn hơn ...
qwr

Bạn có một bằng chứng về sự đúng đắn? Tôi có thể thấy rằng đây là một cách tiếp cận hợp lý, nhưng nhiều hơn thế dường như đòi hỏi khá nhiều công việc.
Peter Taylor

3
@PeterTaylor Thuật toán được đề cập trên Wikipedia: một thuật toán ngây thơ giải quyết vấn đề kịp thời O (n ^ 4) bằng cách kiểm tra các vòng tròn được xác định bởi tất cả các cặp và ba điểm . Nhưng thật không may, không có liên kết đến một bằng chứng.
Arnauld

Nó sẽ đáp ứng vấn đề chính xác làm cho không có giải pháp?
l4m2

1
@Arnauld Nếu bạn cần một số số lạ để tiếp cận, tôi có thể nói rằng điều đó tốt; Nếu nó thậm chí thất bại trong tình huống dễ dàng có thể là một vấn đề
l4m2

14

R , 59 byte

function(x)nlm(function(y)max(Mod(x-y%*%c(1,1i))),0:1)[1:2]

Hãy thử trực tuyến!

Lấy đầu vào như một vector của tọa độ phức tạp. Modlà khoảng cách (mô đun) trong mặt phẳng phức và nlmlà một hàm tối ưu hóa: nó tìm vị trí của tâm (đầu ra là estimate) để thu nhỏ khoảng cách tối đa đến các điểm đầu vào và đưa ra khoảng cách tương ứng (đầu ra là minimum), tức là bán kính . Chính xác đến 3-6 chữ số; chân trang TIO làm tròn đầu ra thành 2 chữ số.

nlmlấy một vectơ số làm đầu vào: y%*%c(1,1i)doanh nghiệp chuyển đổi nó thành một phức tạp.


9

Thạch , 100 98 byte

_²§½
1ịṭƊZIṚṙ€1N1¦,@ṭ@²§$µḢZḢ×Ø1œị$SḤ÷@P§
ZṀ+ṂHƲ€_@Ç+ḷʋ⁸,_²§½ʋḢ¥¥
œc3Ç€;ŒcZÆm,Hñ/$Ʋ€$ñ_ƭƒⱮṀ¥Ðḟ⁸ṚÞḢ

Hãy thử trực tuyến!

Trái ngược với câu trả lời ngôn ngữ Wolfram của tôi , Jelly cần khá nhiều mã để đạt được điều này (trừ khi tôi thiếu thứ gì đó!). Chương trình đầy đủ này lấy danh sách các điểm làm đối số của nó và trả về tâm và bán kính của vòng tròn bao quanh nhỏ nhất. Nó tạo ra các vòng tròn cho tất cả các bộ ba điểm và đường kính cho tất cả các bộ hai điểm, kiểm tra bao gồm tất cả các điểm và sau đó chọn một điểm có bán kính nhỏ nhất.

Mã cho bit make_circumcircle được lấy cảm hứng từ mã tại trang web này , lần lượt lấy cảm hứng từ Wikipedia.


1
Tôi không hiểu mã này, nhưng thay vì đường kính và đường tròn riêng biệt, bạn có thể tạo tất cả các bộ ba điểm với các bản sao và lọc ra danh sách ba điểm giống nhau không?
lirtosiast

2

APL (NARS), ký tự 348, 696 byte

f←{h←{0=k←⍺-1:,¨⍵⋄(k<0)∨k≥i←≢w←⍵:⍬⋄↑,/{w[⍵],¨k h w[(⍳i)∼⍳⍵]}¨⍳i-k}⋄1≥≡⍵:⍺h⍵⋄⍺h⊂¨⍵}
c←{⍵≡⍬:1⋄(x r)←⍵⋄(-r*2)++/2*⍨⍺-x}
p←{(b k)←⍺ ⍵⋄∧/¨1e¯13≥{{⍵{⍵c⍺}¨b}k[⍵]}¨⍳≢k}
s2←{(+/k),√+/↑2*⍨-/k←2÷⍨⍵}
s3←{0=d←2×-.×m←⊃{⍵,1}¨⍵:⍬⋄m[;1]←{+/2*⍨⍵}¨⍵⋄x←d÷⍨-.×m⋄m[;2]←{1⊃⍵}¨⍵⋄y←d÷⍨--.×m⋄(⊂x y),√+/2*⍨(x y)-1⊃⍵}
s←{v/⍨⍵p v←(s2¨2 f⍵)∪s3¨3 f⍵}
s1←{↑v/⍨sn=⌊/sn←{2⊃⍵}¨v←s⍵}

Đây là một 'triển khai' các công thức trong giải pháp Arnauld ... Kết quả và nhận xét:

  s1 (¯8 0)(3 1)(¯6.2 ¯8)(3 9.5)
¯1.6 0.75  9.885469134 
  s1 (7.1 ¯6.9)(¯7 ¯9)(5 10)(¯9.5 ¯8)
¯1.732305109 0.5829680042  11.57602798 
  s1 (0 0)(1 2)(3 ¯4)(4 ¯5)(10 ¯10)
5.5 ¯4  7.5 
  s1 (6 6)(¯6 7)(¯7 ¯6)(6 ¯8)
0 ¯0.5  9.604686356 
  s1 (6 6)(¯6 7)(¯7 ¯6)(6 ¯8)(0 0)(1 2)(3 ¯4)(4 ¯5)(10 ¯10)
2 ¯1.5  11.67261753 
  s1 (6 6)(¯6 7)(¯7 ¯6)(6 ¯8)(1 2)(3 ¯4)(4 ¯5)(10 ¯10)(7.1 ¯6.9)(¯7 ¯9)(5 10)(¯9.5 ¯8)
1.006578947 ¯1.623355263  12.29023186 
  s1 (1 1)(2 2)(3 3)(4 4)
2.5 2.5  2.121320344 
  ⎕fmt s3 (1 1)(2 2)(3 3)(4 4)
┌0─┐
│ 0│
└~─┘

f: tìm thấy sự kết hợp của các hạt alpha trong bộ omega

f←{h←{0=k←⍺-1:,¨⍵⋄(k<0)∨k≥i←≢w←⍵:⍬⋄↑,/{w[⍵],¨k h w[(⍳i)∼⍳⍵]}¨⍳i-k}⋄1≥≡⍵:⍺h⍵⋄⍺h⊂¨⍵}

((X, Y), r) từ bây giờ đại diện cho một độ chính xác của bán kính r và tâm ở (XY).

c: tìm thấy nếu điểm trong nằm trong chu vi ((XY) r) trong ⍵ (kết quả <= 0) nếu nó là bên ngoài (kết quả> 0) Trong trường hợp đầu vào chu vi trong nó là ⍬ làm đầu vào, nó sẽ trả về 1 (ngoài chu vi) mỗi đầu vào có thể trong ⍺.

c←{⍵≡⍬:1⋄(x r)←⍵⋄(-r*2)++/2*⍨⍺-x}

p: nếu ⍵ là một mảng của ((XY) r); với mỗi ((XY) r) trong ghi 1 nếu tất cả các điểm trong mảng là nội bộ đối với ((XY) r) nếu không thì ghi 0 NB Đây là điều không xảy ra vì tôi phải làm tròn đến epsilon = 1e¯ 13. nói cách khác, trong trường hợp giới hạn của các điểm trong mặt phẳng (và có thể được xây dựng trên mục đích), nó không phải là giải pháp được bảo hiểm 100%

p←{(b k)←⍺ ⍵⋄∧/¨1e¯13≥{{⍵{⍵c⍺}¨b}k[⍵]}¨⍳≢k}

s2: từ 2 điểm trong, nó trả về chu vi ở định dạng ((XY) r) có đường kính trong 2 điểm đó

s2←{(+/k),√+/↑2*⍨-/k←2÷⍨⍵}

s3: từ 3 điểm, nó trả về chu vi theo định dạng ((XY) r) đi qua ba điểm đó Nếu có vấn đề (ví dụ: các điểm được căn chỉnh), nó sẽ thất bại và trả về.

s3←{0=d←2×-.×m←⊃{⍵,1}¨⍵:⍬⋄m[;1]←{+/2*⍨⍵}¨⍵⋄x←d÷⍨-.×m⋄m[;2]←{1⊃⍵}¨⍵⋄y←d÷⍨--.×m⋄(⊂x y),√+/2*⍨(x y)-1⊃⍵}

lưu ý rằng -. × tìm định thức của ma trận nxn và

  ⎕fmt ⊃{⍵,1}¨(¯8 0)(3 1)(¯6.2 ¯8)
┌3─────────┐     
3 ¯8    0 1│     |ax  ay 1|
│  3    1 1│   d=|bx  by 1|=ax(by-cy)-bx(ay-cy)+cx(ay-by)=ax(by-cy)+bx(cy-ay)+cx(ay-by)
│ ¯6.2 ¯8 1│     |cx  cy 1|
└~─────────┘

s: từ n điểm trong, nó tìm thấy chu vi loại của những người được tìm thấy bởi s2 hoặc những người thuộc loại s3 có chứa tất cả n điểm.

s←{v/⍨⍵p v←(s2¨2 f⍵)∪s3¨3 f⍵}

s1: từ tập tìm thấy từ s ở trên tính toán những cái có bán kính tối thiểu và trả về cái đầu tiên có bán kính tối thiểu. Ba số dưới dạng mảng (tọa độ thứ nhất và thứ hai là tọa độ của tâm, trong khi số thứ ba là bán kính của chu vi tìm thấy).

s1←{↑v/⍨sn=⌊/sn←{2⊃⍵}¨v←s⍵}

2

Python 2 (PyPy) , 244 242 byte

P={complex(*p)for p in input()}
Z=9e999,
for p in P:
 for q in{p}^P:
	for r in{p}^P:R,S=1j*(p-q),q-r;C=S.imag and S.real/S.imag-1jor 1;c=(p+q-(S and(C*(p-r)).real/(C*R).real*R))/2;Z=min(Z,(max(abs(c-t)for t in P),c.imag,c.real))
print Z[::-1]

Hãy thử trực tuyến!

Điều này sử dụng thuật toán brute-force O (n ^ 4), lặp qua từng cặp và tam giác điểm, tính toán tâm và giữ tâm cần bán kính nhỏ nhất để bao quanh tất cả các điểm. Nó tính toán chu vi của 3 điểm thông qua việc tìm giao điểm của hai đường phân giác vuông góc (hoặc, nếu hai điểm bằng nhau, nó sử dụng trung điểm với điểm thứ ba).


Chào mừng đến với PPCG! Vì bạn đang sử dụng Python 2, bạn có thể lưu 1 byte bằng cách chuyển đổi hai khoảng trắng trên dòng thứ 5 thành một tab.
Stephen

P={x+y*1j for x,y in input()}tiết kiệm 2 byte là tốt.
Ông Xcoder

1

Python 212 190 byte

Giải pháp này không chính xác và tôi phải làm việc ngay bây giờ vì vậy tôi không có thời gian để sửa nó.

a=eval(input())
b=lambda a,b: ((a[0]-b[0])**2+(a[1]-b[1])**2)**.5
c=0
d=1
for e in a:
    for f in a:
        g=b(e,f)
        if g>c:
            c=g
            d=[e,f]
print(((d[0][0]+d[1][0])/2,(d[0][1]+d[1][1])/2,c/2))

Hãy thử trực tuyến!

Tôi đã tìm ra hai điểm nào xa nhất và sau đó tôi tạo ra một phương trình cho một vòng tròn dựa trên những điểm đó!

Tôi biết đây không phải là con trăn ngắn nhất, nhưng nó là thứ tốt nhất tôi có thể làm! Ngoài ra đây là nỗ lực đầu tiên của tôi khi thực hiện một trong những điều này, vì vậy hãy hiểu!


2
Điều này có thể được đánh golf thêm một số. Ví dụ, bạn có thể rút ngắn if g>c:\n c=g\n d=[e,f]để if g>c:c=g;d=[e,f]tiết kiệm cho bạn rất nhiều khoảng trắng. Tôi không nghĩ rằng bạn cần phải khởi tạo d trước đó, cũng sử dụng hai biến và E,F=e,ftrong dòng 10 sẽ làm cho bạn printngắn hơn rất nhiều. Tôi nghĩ rằng một giải pháp với maxvà một sự hiểu biết danh sách thậm chí sẽ ngắn hơn hai vòng, nhưng tôi có thể sai. Đáng buồn thay, tuy nhiên, giải pháp của bạn là không chính xác. Đối với các điểm (-1,0), (0,1,41), (0,5, 0), (1,0) giải pháp của bạn sẽ tính một vòng tròn quanh 0 với bán kính 1. Nhưng điểm (1, 1.41) không nằm trong đó vòng tròn.
Cú đen Kai

Chào mừng bạn Cảm ơn bạn vì câu trả lời. Như đã chỉ ra trong nhận xét trên, giải pháp của bạn là không chính xác. Một gợi ý cho giải pháp brute-force: Vòng tròn nhỏ nhất có thể chạm vào hai điểm hoặc ba điểm. Bạn có thể bắt đầu tính toán phương trình cho đường tròn chạm vào từng cặp điểm và kiểm tra xem có điểm nào bao quanh tất cả các điểm không. Sau đó tính toán phương trình cho đường tròn chạm vào từng bộ ba điểm và kiểm tra xem có một điểm nào bao quanh tất cả các điểm không. Khi bạn nhận được tất cả các vòng tròn có thể, chọn một vòng tròn có bán kính nhỏ nhất.
Barranka

1
Được rồi tôi sẽ cố gắng làm cho nó hoạt động, và sau đó tôi sẽ cập nhật câu trả lời. Tôi cần tìm ra cách kiểm tra nếu một điểm được chứa trong một vòng tròn.
Ben Morrison

Khi bạn có tâm và bán kính của vòng tròn, hãy kiểm tra xem khoảng cách giữa tâm và mỗi điểm nhỏ hơn hoặc bằng bán kính; nếu điều kiện đó đúng với tất cả các điểm, thì vòng tròn đó là một ứng cử viên
Barranka
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.