Golf lingkaran terkecil!

29

Masalah:

Dengan serangkaian titik yang tidak kosong di pesawat Cartesian, temukan lingkaran terkecil yang melingkupinya semua ( tautan Wikipedia ).

Masalah ini sepele jika jumlah titik tiga atau kurang (jika ada satu titik, lingkaran memiliki jari-jari nol; jika ada dua titik, segmen garis yang menghubungkan titik-titik tersebut adalah diameter lingkaran; jika ada tiga (non-colinear) poin, dimungkinkan untuk mendapatkan persamaan lingkaran yang menyentuh mereka semua jika mereka membentuk segitiga non-tumpul, atau lingkaran yang menyentuh hanya dua titik dan menutup ketiga jika segitiga tumpul). Jadi, demi tantangan ini, jumlah poin harus lebih dari tiga.

Tantangan:

  • Input: Daftar 4 atau lebih poin non-colinear. Poin harus memiliki koordinat X dan Y; koordinat bisa mengapung. Untuk meringankan tantangan, tidak ada dua poin yang harus berbagi koordinat X yang sama.
    Sebagai contoh:[(0,0), (2,1), (5,3), (-1,-1)]
  • Keluaran: Satu tupel nilai, (h,k,r)sehingga (xh)2+(yk)2=r2 adalah persamaan dari lingkaran terkecil yang melingkupi semua titik.

Aturan:

  • Anda dapat memilih metode input apa pun yang sesuai dengan program Anda.
  • Output harus dicetak ke STDOUTatau dikembalikan oleh suatu fungsi.
  • "Normal", tujuan umum, bahasa lebih disukai, tetapi esolang apa pun dapat diterima.
  • Anda dapat mengasumsikan bahwa poinnya tidak colinear.
  • Ini adalah kode-golf, jadi program terkecil dalam byte menang. Pemenang akan dipilih satu minggu setelah tantangan diposting.
    • Harap sertakan bahasa yang Anda gunakan dan panjang dalam byte sebagai tajuk di baris pertama jawaban Anda: # Language: n bytes

Kasus uji:

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

Selamat bermain golf !!!


Tantangan terkait:

Barranka
sumber
8
“Jika ada tiga titik (non co-linear), dimungkinkan untuk mendapatkan persamaan lingkaran yang menyentuh semuanya” —tapi itu mungkin bukan lingkaran penutup terkecil. Untuk tiga simpul segitiga tumpul, lingkaran penutup terkecil adalah lingkaran yang diameternya adalah sisi terpanjang.
Anders Kaseorg
2
@Arnauld Sama seperti Anda. Untuk test case 2, saya mendapatkan center (-1.73, 0.58) dan untuk test case 3 (5.5, -4).
Robin Ryder
@Arnauld terima kasih atas komentar Anda. Saya telah mengedit posting yang sesuai
Barranka
@Arnauld oops, maaf. Memang. Aldo, mengoreksi dengan pengamatan Anda
Barranka

Jawaban:

26

Bahasa Wolfram (Mathematica) , 28 27 byte

#~BoundingRegion~"MinDisk"&

Cobalah online!

Built-in berguna di sini. Output adalah objek disk dengan pusat dan jari-jari. Seperti yang lain, saya telah menemukan kasus uji 2 dan 3 berbeda dengan pertanyaan.

Terima kasih kepada @ lirtosiast karena telah menghemat satu byte!

Jika daftar diperlukan sebagai output, ini dapat dilakukan dalam 35 byte (dengan biaya tambahan 8 byte) . Terima kasih kepada @Roman untuk menunjukkan ini.

Nick Kennedy
sumber
3
Saya mengharapkan sebuah Mathematica built-in. Tapi saya tidak berharap Mathematica memiliki "objek disk".
Robin Ryder
36 byte untuk mendapatkan format output yang benar:Append@@BoundingRegion[#,"MinDisk"]&
Roman
20

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

Mengembalikan array [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

Cobalah online!

atau lihat versi yang diformat

Bagaimana?

metode

(A,B)(X,Y,r)AB

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

(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

(x,y)

(xX)2+(yY)2r

Dan kami akhirnya mengembalikan lingkaran valid terkecil.

Pelaksanaan

(X,Y)d0q=Cx2+Cy2

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

F(j,k)

  • (ByCy,CyAy)X
  • (CxBx,AxCx)Y

Fs(X,Y)d=0

Arnauld
sumber
mungkin menulis pengoptimal numerik tipe-Newton lebih pendek ...
qwr
Apakah Anda memiliki bukti kebenaran? Saya dapat melihat bahwa ini adalah pendekatan yang masuk akal, tetapi lebih dari itu tampaknya memerlukan sedikit usaha.
Peter Taylor
3
@PeterTaylor Algoritma disebutkan di Wikipedia: algoritma naif memecahkan masalah dalam waktu O (n ^ 4) dengan menguji lingkaran yang ditentukan oleh semua pasangan dan tiga kali lipat poin . Namun sayangnya, tidak ada tautan ke bukti.
Arnauld
Apakah akan memenuhi masalah ketepatan sehingga tidak ada solusi?
14m2
1
@Arnauld Jika Anda membutuhkan beberapa nomor aneh untuk dijangkau, saya dapat mengatakan itu tidak apa-apa; Jika bahkan gagal dalam situasi mudah yang mungkin menjadi masalah
l4m2
14

R , 59 byte

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

Cobalah online!

Mengambil input sebagai vektor koordinat kompleks. Modadalah jarak (modulus) dalam bidang kompleks dan nlmmerupakan fungsi optimisasi: ia menemukan posisi pusat (keluaran sebagai estimate) yang meminimalkan jarak maksimum ke titik input, dan memberikan jarak yang sesuai (keluaran sebagai minimum), yaitu jari-jari . Akurat hingga 3-6 digit; footer TIO membulatkan output menjadi 2 digit.

nlmmengambil vektor numerik sebagai input: y%*%c(1,1i)bisnis mengubahnya menjadi kompleks.

Robin Ryder
sumber
9

Jelly , 100 98 byte

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

Cobalah online!

Berbeda dengan jawaban bahasa Wolfram saya , Jelly membutuhkan cukup banyak kode untuk mencapai ini (kecuali saya kehilangan sesuatu!). Program lengkap ini mengambil daftar poin sebagai argumennya dan mengembalikan pusat dan jari-jari lingkaran terlampir terkecil. Ini menghasilkan circumcircles untuk semua set tiga titik, dan diameter untuk semua set dua titik, cek yang mencakup semua titik dan kemudian memilih satu dengan jari-jari terkecil.

Kode untuk bit make_circumcircle terinspirasi oleh kode di situs ini , yang pada gilirannya terinspirasi oleh Wikipedia.

Nick Kennedy
sumber
1
Saya tidak mengerti kode ini, tetapi daripada diameter dan lingkaran secara terpisah, dapatkah Anda menghasilkan semua set tiga titik dengan duplikat dan memfilter daftar tiga titik identik?
lirtosiast
2

APL (NARS), 348 karakter, 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⍵}

Ini adalah salah satu 'implementasi' dari formula dalam solusi Arnauld ... Hasil dan komentar:

  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: menemukan kombinasi alpha ojets di set omega

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

((X, Y), r) dari sekarang mewakili satu lingkaran dari jari-jari r dan pusat di (XY).

c: menemukan jika titik di ⍺ berada di dalam keliling ((XY) r) di ⍵ (hasil <= 0) atau itu eksternal (hasil> 0) Dalam hal input lingkar di ⍵ itu adalah ⍬ sebagai input, itu akan mengembalikan 1 (di luar keliling) setiap kemungkinan input di ⍺.

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

p: jika ⍵ adalah array dari ((XY) r); untuk masing-masing ((XY) r) di ⍵ menulis 1 jika semua titik dalam array ⍺ adalah internal ke ((XY) r) jika tidak menulis 0 NB Berikut adalah sesuatu yang tidak berjalan karena saya harus membulatkan ke epsilon = 1e¯ 13. dengan kata lain dalam kasus batas poin di pesawat (dan mungkin dibangun dengan sengaja) itu bukan solusi 100% diasuransikan

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

s2: dari 2-titik di ⍵, ia mengembalikan keliling dalam format ((XY) r) yang memiliki diameter dalam 2 titik tersebut

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

s3: dari 3 titik itu mengembalikan keliling dalam format ((XY) r) melewati tiga poin Jika ada masalah (misalnya poin disejajarkan), itu akan gagal dan kembali ⍬.

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

perhatikan bahwa -. × menemukan penentu matriks nxn dan

  ⎕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: dari n titik di ⍵, ia menemukan tipe keliling dari yang ditemukan oleh s2 atau dari tipe s3 yang berisi semua n poin.

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

s1: dari set yang ditemukan dari s di atas menghitung yang memiliki radius minimum dan mengembalikan yang pertama yang memiliki radius minimal. Tiga angka sebagai array (koordinat pertama dan kedua adalah koordinat tengah, sedangkan yang ketiga adalah jari-jari keliling yang ditemukan).

s1←{↑v/⍨sn=⌊/sn←{2⊃⍵}¨v←s⍵}
RosLuP
sumber
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]

Cobalah online!

Ini menggunakan algoritma brute-force O (n ^ 4), iterasi melalui setiap pasangan dan segitiga titik, menghitung pusat, dan menjaga pusat yang membutuhkan jari-jari terkecil untuk melampirkan semua titik. Ini menghitung keliling dari 3 poin melalui menemukan persimpangan dari dua garis-garis tegak lurus (atau, jika dua titik sama, ia menggunakan titik tengah dengan yang ketiga).

Vash3r
sumber
Selamat datang di PPCG! Karena Anda menggunakan Python 2, Anda dapat menyimpan 1 byte dengan mengubah dua spasi pada baris ke-5 menjadi sebuah tab.
Stephen
P={x+y*1j for x,y in input()}menghemat 2 byte juga.
Tn. Xcoder
1

Python 212 190 byte

Solusi ini salah, dan saya harus bekerja sekarang jadi saya tidak punya waktu untuk memperbaikinya.

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

Cobalah online!

Saya menemukan dua titik mana yang paling jauh dan kemudian saya menghasilkan persamaan untuk lingkaran berdasarkan dari titik-titik itu!

Saya tahu ini bukan yang terpendek dalam python, tapi itu yang terbaik yang bisa saya lakukan! Juga ini adalah upaya pertama saya untuk melakukan salah satu dari ini, jadi harap mengerti!

Ben Morrison
sumber
2
Ini bisa bermain golf lagi. Misalnya, Anda dapat mempersingkat if g>c:\n c=g\n d=[e,f]untuk if g>c:c=g;d=[e,f], menghemat banyak spasi. Saya tidak berpikir Anda perlu menginisialisasi d sebelumnya, juga menggunakan dua variabel dan E,F=e,fdi baris 10 akan membuat Anda printjauh lebih pendek. Saya pikir solusi dengan maxdan pemahaman daftar akan lebih pendek dari dua loop, tapi saya mungkin salah. Sayangnya, solusi Anda tidak tepat. Untuk titik (-1,0), (0,1.41), (0,5, 0), (1,0) solusi Anda menghitung lingkaran di sekitar 0 dengan jari-jari 1. Tetapi titik (1, 1,41) tidak dalam lingkaran.
Black Owl Kai
Selamat datang! Terima kasih atas jawaban Anda. Seperti yang ditunjukkan dalam komentar di atas, solusi Anda tidak benar. Sebuah petunjuk untuk solusi brute-force: Lingkaran terkecil yang mungkin menyentuh dua poin atau tiga poin. Anda bisa mulai menghitung persamaan untuk lingkaran yang menyentuh setiap pasangan poin dan memeriksa apakah ada yang melingkupi semua poin. Kemudian hitung persamaan untuk lingkaran yang menyentuh setiap triplet poin dan periksa apakah ada yang melingkupi semua poin. Setelah Anda mendapatkan semua lingkaran yang mungkin, pilih satu dengan jari-jari terkecil.
Barranka
1
Baiklah saya akan mencoba membuatnya bekerja, dan kemudian saya akan memperbarui jawabannya. Saya perlu mencari cara untuk memeriksa apakah suatu titik terkandung dalam lingkaran.
Ben Morrison
Setelah Anda memiliki pusat dan jari-jari lingkaran, periksa apakah jarak antara pusat dan setiap titik kurang dari atau sama dengan jari-jari; jika kondisi itu berlaku untuk semua poin, lingkaran itu adalah kandidat
Barranka