En küçük daireye golf atın!


29

Sorun:

Kartezyen düzleminde boş olmayan bir nokta kümesi göz önüne alındığında, hepsini çevreleyen en küçük daireyi bulun ( Wikipedia link ).

Nokta sayısı üç veya daha az ise bu sorun önemsizdir (bir nokta varsa, dairenin yarıçapı sıfırdır; iki nokta varsa, noktaları birleştiren çizgi kesimi dairenin çapıdır; varsa üç (colinear olmayan) nokta, geniş olmayan bir üçgen oluştururlarsa hepsine dokunan bir çemberin denklemini, ya da sadece iki noktaya dokunan ve üçgen genişse üçüncüyü çevreleyen bir çemberin denklemini elde etmek mümkündür). Bu nedenle, bu zorluğun iyiliği için, puan sayısının üçten fazla olması gerekir.

Meydan okuma:

  • Giriş: 4 veya daha fazla eşlenik olmayan noktaların listesi. Noktaların X ve Y koordinatlarına sahip olması gerekir; koordinatlar değişken olabilir. Mücadeleyi kolaylaştırmak için, hiçbir iki nokta aynı X koordinatını paylaşmamalıdır.
    Örneğin:[(0,0), (2,1), (5,3), (-1,-1)]
  • Çıkış: bir değerler kayıt düzeni (h,k,r), öyle ki (x-h)2+(y-k)2=r2 tüm noktaları çevreleyen en küçük dairenin denklemidir.

Kurallar:

  • Programınıza uygun giriş yöntemini seçebilirsiniz.
  • Çıktı STDOUTbir işlev tarafından yazdırılmalı veya iade edilmelidir .
  • "Normal", genel amaçlı, diller tercih edilir, ancak herhangi bir esolang kabul edilebilir.
  • Noktaların eş zamanlı olmadığını varsayabilirsin.
  • Bu kod golf, yani bayt cinsinden en küçük program kazanır. Kazanan, yarışmanın yayınlanmasından bir hafta sonra seçilecektir.
    • Lütfen kullandığınız dili ve bayt cinsinden uzunluğu yanıtınızın ilk satırına ekleyin: # Language: n bytes

Test durumları:

  • 1:
    • Giriş: [(-8,0), (3,1), (-6.2,-8), (3,9.5)]
    • Çıktı: [-1.6, 0.75, 9.89]
  • 2:
    • Giriş: [(7.1,-6.9), (-7,-9), (5,10), (-9.5,-8)]
    • Çıktı: [-1.73, 0.58, 11.58]
  • 3:
    • Giriş: [(0,0), (1,2), (3,-4), (4,-5), (10,-10)]
    • Çıktı: [5.5, -4, 7.5]
  • 4:
    • Giriş: [(6,6), (-6,7), (-7,-6), (6,-8)]
    • Çıktı: [0, -0.5, 9.60]

Mutlu golf !!!


İlgili zorluk:



8
“Üç (doğrusal olmayan) nokta varsa, hepsine dokunan bir çemberin denklemini elde etmek mümkündür” - ama en küçük çember olmayabilir. Geniş bir üçgenin üç köşesi için, en küçük çevre dairesi, çapı en uzun taraf olandır.
Anders Kaseorg

2
@Arnauld Sizinle aynı. Test durumu 2 için, merkeze (-1.73, 0.58) ve test durumu 3'e (5.5, -4) ulaşıyorum.
Robin Ryder

@ Yorumunuz için teşekkürler.
Gönderiyi

@Arnauld, üzgünüm. Aslında. Aldo, gözlemlerini düzeltirken
Barranka

Yanıtlar:


26

Wolfram Dili (Mathematica) , 28 27 bayt

#~BoundingRegion~"MinDisk"&

Çevrimiçi deneyin!

Yerleşikler burada kullanışlıdır. Çıktı, merkezi ve yarıçapı olan bir disk nesnesidir. Diğerleri gibi, 2. ve 3. test vakalarını sorudan farklı buldum.

Bir bayt tasarrufu için @ lirtosiast teşekkürler!

Çıktı olarak bir liste gerekiyorsa, bu 35 baytta (ek bir 8 bayt pahasına) yapılabilir . @Roman'a bunu gösterdiği için teşekkürler.


3
Bir Mathematica yerleşik buluyordum. Ancak Mathematica'nın “disk nesneleri” olmasını beklemiyordum.
Robin Ryder

Çıkış biçimini doğru almak için 36 byte :Append@@BoundingRegion[#,"MinDisk"]&
Roman

20

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

Bir dizi döndürür [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

Çevrimiçi deneyin!

veya biçimlendirilmiş bir sürüm görmek

Nasıl?

Yöntem

Her bir nokta çifti için (A,B) , daireyi oluştururuz(X,Y,r)çapıAB olan ( X , Y , r ) oluştururuz .

X=birx+Bx2,Y=biry+By2,r=(birx-Bx2)2+(biry-By2)2

Farklı noktaların (bir,B,C) her üçlü için daireyi (X,Y,r)birBC üçgenini çevreleyen ).

d=birx(By-Cy)+Bx(Cy-biry)+Cx(biry-By)
X=(birx2+biry2)(By-Cy)+(Bx2+By2)(Cy-biry)+(Cx2+Cy2)(biry-By)2d
Y=(birx2+biry2)(Cx-Bx)+(Bx2+By2)(birx-Cx)+(Cx2+Cy2)(Bx-birx)2d
r=(X-birx)2+(Y-biry)2

Üretilen her daire için, her noktanın olup olmadığını test ederiz (x,y) içine alınmış:

(x-X)2+(y-Y)2r

Ve sonunda en küçük geçerli çevreyi döndürdük.

uygulama

JS kodunda, üçgenin sınırlanmış çemberi için hesaplanacak formül (X,Y) biraz basitleştirilmiştir. Varsayarak d0 , tanımladığımızı q=Cx2+Cy2

X=(birx2+biry2-q)(By-Cy)+(Bx2+By2-q)(Cy-biry)2d
Y=(birx2+biry2-q)(Cx-Bx)+(Bx2+By2-q)(birx-Cx)2d

F(j,k)

  • (By-Cy,Cy-biry)X
  • (Cx-Bx,birx-Cx) içinY

Fs(X,Y)d=0 , yani üçgenin dejenere olduğu ve bunun yerine çapı kullanmamız gerektiği anlamına gelir.


Newton tipi bir sayısallaştırıcı yazma belki daha kısadır ...
qwr

Doğruluk kanıtı var mı? Bunun makul bir yaklaşım olduğunu görebiliyorum, fakat bundan daha fazlası için biraz çalışma gerektiriyor.
Peter Taylor

3
@PeterTaylor Algoritmanın Wikipedia'da bahsedilmesi: saf bir algoritma, tüm zamanların ve üçlü noktaların belirlediği daireleri test ederek O (n ^ 4) zamanındaki sorunu çözer . Fakat ne yazık ki, bir kanıtla bağlantısı yoktur.
Arnauld

Hassasiyet sorununu orada çözemez mi?
l4m2

1
@Arnauld Ulaşmak için bazı garip numaralara ihtiyacınız varsa, bunun iyi olduğunu söyleyebilirim; Bir sorun olabilir kolay durumda bile başarısız olursa
l4m2

14

R, , 59 bayt

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

Çevrimiçi deneyin!

Girdiyi karmaşık koordinatların bir vektörü olarak alır. Modkarmaşık düzlemde mesafedir (modül) venlm bir optimizasyon işlevidir: merkezin konumunu bulur (çıktı olarakestimate giriş noktalarına maksimum mesafeyi en aza indiren ) ve karşılık gelen mesafeyi (çıkış olarak minimum), yani yarıçapı verir . 3-6 haneye kadar doğru; TIO altbilgisi çıkışı 2 basamağa yuvarlar.

nlmgirdi olarak sayısal bir vektör alır: y%*%c(1,1i)işletme onu bir komplekse dönüştürür.


9

Jöle , 100 98 bayt

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

Çevrimiçi deneyin!

Wolfram dili cevabımın aksine , Jelly'in bunu başarabilmesi için çok fazla koda ihtiyacı var (bir şeyi kaçırmıyorsam!). Bu tam program argüman olarak noktaların listesini alır ve en küçük çevreleyen dairenin merkezini ve yarıçapını döndürür. Üç nokta kümesinin tamamı için çemberler ve iki nokta kümesinin tümü için çaplar oluşturur, tüm noktaları içeren denetimler ve en küçük yarıçapa sahip olanı seçer.

Make_circumcircle bit kodu, bu sitedeki koddan ve sırayla Wikipedia'dan ilham aldı.


1
Bu kodu anlamıyorum, fakat çapları ve çemberleri ayrı ayrı değil, üç noktadan oluşan tüm kümeleri iki kopya oluşturabilir ve üç özdeş noktaların listelerini filtreleyebilir misiniz?
lirtosiast

2

APL (NARS), 348 karakter, 696 bayt

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⍵}

Bu, Arnauld çözümündeki formüllerin bir 'uygulaması' ... Sonuçları ve yorumları:

  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: omega setindeki alfa jet kombinasyonunu bulur

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

((X, Y), r), bundan sonra bir X yarıçapı ve merkezin (XY) içindeki bir çevresini temsil eder.

c: in noktasının çevrenin ((XY) r) ⍵ (sonuç <= 0) içinde olup olmadığını bulur (dış> sonuç) (0) ⍵ 'da çevre girişi durumunda, giriş olarak ⍬ possible 'daki olası girişlerin her birini 1 (çevre dışından) döndürür.

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

p: eğer ⍵ ((XY) r) dizisi ise; in'daki ((XY) r) 'nin her biri için, ⍺ dizisindeki tüm noktalar ((XY) r)' nin içindeyse, 1 yazıyor, aksi takdirde 0 NB yazar. 13. Başka bir deyişle, uçaktaki puan limitlerini sınırlandırılmış durumda (ve muhtemelen bilerek yapılmış),% 100 çözüm sigortalı değildir

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

s2: 2 puntodan ⍵, çevreyi bu 2 noktadaki çapa sahip ((XY) r) biçiminde döndürür

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

s3: 3 noktadan çevreyi, bu üç noktadan geçen ((XY) r) biçiminde döndürür. Sorun varsa (örneğin, noktalar hizalanır), başarısız olur ve return ile döner.

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

- - × nxn matrisinin determinantını bulduğu ve

  ⎕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: in'daki n noktalarından, s2 tarafından bulunanların veya tüm n noktalarını içeren s3 tipinin tiplerini bulur.

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

s1: yukarıdakilerden bulunan kümeden minimum yarıçapa sahip olanları hesaplar ve ilk yarıçapa sahip olanı döndürür. Dizi olarak üç sayı (birinci ve ikinci koordinatlar merkezin koordinatlarıdır, üçüncüsü bulunan çevrenin yarıçapıdır).

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

2

Python 2 (PyPy) , 244 242 bayt

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]

Çevrimiçi deneyin!

Bu, her bir çift ve nokta üçgeni boyunca yinelenen, merkezi hesaplayan ve tüm noktaları içine alan en küçük yarıçapa ihtiyacı olan merkezi koruyan kaba kuvvet O (n ^ 4) algoritmasını kullanır. İki dikey bisektörün kesişimini bularak 3 puanın çevresini hesaplar (veya eğer iki puan eşit ise üçüncü puan ile orta noktayı kullanır).


PPCG'ye Hoşgeldiniz! Python 2 kullandığınız için, 5. satırdaki iki boşluğu sekmeye dönüştürerek 1 byte tasarruf edebilirsiniz.
Stephen,

P={x+y*1j for x,y in input()}2 bayt da kaydeder.
Bay Xcoder

1

piton 212 190 bayt

Bu çözüm yanlıştır ve şimdi çalışmak zorundayım, bu yüzden düzeltmek için zamanım yok.

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))

Çevrimiçi deneyin!

Hangi iki noktanın en uzak olduğunu buldum ve sonra bu noktalardan yola çıkarak bir çember için bir denklem oluşturdum!

Bunun pythondaki en kısa olmadığını biliyorum, ama yapabileceğimin en iyisi! Ayrıca bu benim bunlardan birini yapmadaki ilk denemem, o yüzden lütfen anlayın!


2
Bu biraz daha golf oynayabilir. Örneğin, kısaltabilirsiniz if g>c:\n c=g\n d=[e,f]için if g>c:c=g;d=[e,f]size bir çok bosluk tasarruf. Önceden d başlatmanız gerektiğini sanmıyorum, ayrıca iki değişken kullanmak ve E,F=e,f10. satırda printçok daha kısa sürecek . Bence bir çözüm maxve bir liste kavrayışı iki döngüden bile daha kısa olurdu, ama yanlış olabilirim. Ne yazık ki, ancak, çözümünüz doğru değil. (-1,0), (0,1.41), (0.5, 0), (1,0) noktaları için, çözümünüz yarıçapı 1 olan bir çember hesaplar. Fakat nokta (1, 1.41) bunun içinde değildir. daire.
Kara Baykuş Kai,

Hoşgeldiniz! Cevabınız için teşekkür ederim. Yukarıdaki açıklamada belirtildiği gibi, çözümünüz doğru değil. Kaba kuvvet çözümü için bir ipucu: Mümkün olan en küçük daire iki noktaya veya üç noktaya dokunuyor. Her bir nokta çiftine temas eden dairenin denklemini hesaplamaya başlayabilir ve tüm noktaları saran bir tane olup olmadığını kontrol edebilirsiniz. Ardından, her üçlü noktaya dokunan dairenin denklemini hesaplayın ve tüm noktaları saran bir tane olup olmadığını kontrol edin. Mümkün olan tüm daireleri elde ettikten sonra, en küçük yarıçapa sahip olanı seçin.
Barranka

1
Tamam, çalışmasını sağlamaya çalışacağım ve sonra cevabı güncelleyeceğim. Bir noktanın daire içinde olup olmadığını nasıl kontrol edeceğimi bulmam gerekiyor.
Ben Morrison

Dairenin merkezine ve yarıçapına sahip olduğunuzda, merkez ile her nokta arasındaki mesafenin yarıçaptan küçük veya eşit olup olmadığını kontrol edin; eğer bu durum tüm noktalar için geçerliyse, bu daire bir adaydır
Barranka
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.