Bir 2D nokta kümesinin dışbükey gövdesini bulun


20

Bir çivi setini tahta bir tahtaya çekiçleyip etrafına bir lastik bant sardığınızda , bir Konveks Gövde elde edersiniz .

resim açıklamasını buraya girin

Göreviniz, kabul etmeye karar verirseniz, verilen 2B nokta kümesinin dışbükey gövdesini bulmaktır .


Bazı kurallar:

  • Bir işlev olarak yazın, noktanın liste koordinatları (istediğiniz herhangi bir biçimde) argüman
  • Çıktı, herhangi birinden başlayarak saat yönünde veya saat yönünün tersine listelenen dışbükey gövdedeki noktaların listesi olmalıdır.
  • Çıktı listesi, her bir noktanın koordinatlarının açıkça ayırt edilebildiği herhangi bir makul formatta olabilir. (Örneğin bir loş liste DEĞİL {0.1, 1.3, 4, ...})
  • Dışbükey gövdenin bir segmentindeki üç veya daha fazla nokta hizalanmışsa, çıktıda yalnızca iki uç tutulmalıdır

Örnek veri:

Numune 0

Giriş:

{{1, 1}, {2, 2}, {3, 3}, {1, 3}}

Çıktı:

{{3, 3}, {1, 3}, {1, 1}}

Mathematica grafikleri (Rakamlar sadece açıklayıcıdır)

Numune 1

Giriş:

{{4.4, 14}, {6.7, 15.25}, {6.9, 12.8}, {2.1, 11.1}, {9.5, 14.9}, 
 {13.2, 11.9}, {10.3, 12.3}, {6.8, 9.5}, {3.3, 7.7}, {0.6, 5.1}, {5.3, 2.4}, 
 {8.45, 4.7}, {11.5, 9.6}, {13.8, 7.3}, {12.9, 3.1}, {11, 1.1}}

Çıktı:

{{13.8, 7.3}, {13.2, 11.9}, {9.5, 14.9}, {6.7, 15.25}, {4.4, 14}, 
 {2.1, 11.1}, {0.6, 5.1}, {5.3, 2.4}, {11, 1.1}, {12.9, 3.1}}

Mathematica grafikleri

Numune 2

Giriş:

{{1, 0}, {1, 1}, {1, -1}, {0.68957, 0.283647}, {0.909487, 0.644276}, 
 {0.0361877, 0.803816}, {0.583004, 0.91555}, {-0.748169, 0.210483}, 
 {-0.553528, -0.967036}, {0.316709, -0.153861}, {-0.79267, 0.585945},
 {-0.700164, -0.750994}, {0.452273, -0.604434}, {-0.79134, -0.249902}, 
 {-0.594918, -0.397574}, {-0.547371, -0.434041}, {0.958132, -0.499614}, 
 {0.039941, 0.0990732}, {-0.891471, -0.464943}, {0.513187, -0.457062}, 
 {-0.930053, 0.60341}, {0.656995, 0.854205}}

Çıktı:

{{1, -1}, {1, 1}, {0.583004, 0.91555}, {0.0361877, 0.803816}, 
 {-0.930053, 0.60341}, {-0.891471, -0.464943}, {-0.700164, -0.750994}, 
 {-0.553528, -0.967036}}

Mathematica grafikleri

Standart kod golf kuralları geçerlidir. Geçici geometri kitaplığı yok. Daha kısa kod kazanır.

Düzenle 1

Burada algoritmik bir cevap arıyoruz , MatLab'da veya Mathematica'da bunun gibi önceden programlanmış bir dışbükey gövde bulucu değil

Düzenle 2

Yorumları ve ek bilgileri yanıtlama:

  1. Giriş listesinin size uygun minimum sayıda nokta içerdiğini varsayabilirsiniz. Ancak, hizalanmış (alt) kümelerin uygun şekilde işlemesini sağlamalısınız.
  2. Giriş listesinde tekrarlanan noktalar bulabilirsiniz
  3. Maksimum nokta sayısı yalnızca kullanılabilir bellekle sınırlandırılmalıdır
  4. Yeniden "kayan nokta": Ondalık koordinatları olan girdi listelerini örneklerde verilenlerle işleyebilmeniz gerekir. Sen olabilir bir kayan nokta gösterimi kullanılarak bunu

.


2
MATLAB'ın bunu kazanacağını tahmin ediyorum .
Paul R

En az 3 puan olduğunu varsayabilir miyiz? Puanların farklı olduğunu varsayabilir miyiz? Kayan nokta koordinatlarını desteklememiz gerekiyor mu?
Peter Taylor

@PeterTaylor örneği son cevabın doğru olduğunu gösterir
John Dvorak

Girdinin üzerine yazabilir miyiz?
John Dvorak

Eşdoğrusal noktaların tutarlı bir şekilde ele alınmasındaki sorun, yuvarlama sorunları olmasıdır. Hata yapmamıza izin verilmeli.
John Dvorak

Yanıtlar:


2

Ruby, 168 karakter

C=->q{r=[]
f=m=q.sort[0]
t=-0.5
(_,_,t,*f=q.map{|x,y|a=x-f[0]
b=y-f[1]
[0==(d=a*a+b*b)?9:(-t+e=Math.atan2(b,a)/Math::PI)%2,-d,e,x,y]}.sort[0]
r<<=f)while
!r[1]||f!=m
r}

Bu yakut kodu ayrıca hediye sarma algoritmasını kullanır. İşlev Cbir dizi noktayı kabul eder ve dışbükey gövdeyi dizi olarak döndürür.

Örnek:

>p C[[[4.4, 14], [6.7, 15.25], [6.9, 12.8], [2.1, 11.1], [9.5, 14.9], 
     [13.2, 11.9], [10.3, 12.3], [6.8, 9.5], [3.3, 7.7], [0.6, 5.1], [5.3, 2.4], 
     [8.45, 4.7], [11.5, 9.6], [13.8, 7.3], [12.9, 3.1], [11, 1.1]]]

[[5.3, 2.4], [11, 1.1], [12.9, 3.1], [13.8, 7.3], [13.2, 11.9], [9.5, 14.9], [6.7, 15.25], [4.4, 14], [2.1, 11.1], [0.6, 5.1]]

2

Mathematica 151

hala devam ediyor

f = For[t = Sort@#; n = 1; l = Pi; a = ArcTan; c@1 = t[[1]],
       n < 2 || c@n != c@1, 
       n++,
      (l = a @@ (# - c@n); c[n + 1] = #) & @@
      t[[Ordering[Mod[a@## - l, 2 Pi] & @@ (#2 - #1) & @@@ Tuples@{{c@n}, t}, 1]]]] &

test yapmak:

ClearAll[a, c, t];
s = {{1, 0}, {0.68957, 0.283647}, {0.909487, 0.644276}, {0.0361877, 0.803816}, 
     {0.583004, 0.91555}, {-0.748169, 0.210483}, {-0.553528, -0.967036}, 
     {0.316709, -0.153861}, {-0.79267, 0.585945}, {-0.700164, -0.750994}, 
     {0.452273, -0.604434}, {-0.79134, -0.249902}, {-0.594918, -0.397574}, 
     {-0.547371, -0.434041}, {0.958132, -0.499614}, {0.039941, 0.0990732}, 
     {-0.891471, -0.464943}, {0.513187, -0.457062}, {-0.930053, 0.60341}, 
     {0.656995, 0.854205}};
f@s
Show[Graphics@Line@Table[c@i, {i, n}], 
     ListPlot[{t, Table[c@i, {i, n}]}, 
     PlotStyle -> {PointSize[Medium], PointSize[Large]}, 
     PlotRange -> All]]

resim açıklamasını buraya girin


1

CoffeeScript, 276:

f=($)->z=$[0];e.r=Math.atan2(e.x-z.x,e.y-z.y)for e in $;$.sort((x,y)->(x.r>y.r)-(x.r<y.r));(loop(a=$[i-1]||$[$.length-1];b=$[i];c=$[i+1]||$[0];break if!b;s=(b.x-a.x)*(c.y-b.y)-(b.y-a.y)*(c.x-b.x);break if s<0||!s&&(a.x-b.x)*(b.x-c.x)<0;$.splice i,1))for i in [$.length-1..0];$

İşlevin erişilebilir olması gerekmiyorsa, f=iki karakteri daha tıraş etmek için kaldırın .

Girdi / çıktı tek bir nokta dizisidir ve her bir nokta x,y özellikler . Giriş dizisi değiştirilir ve döndürülür (ikincisi gerekli değilse, son iki karakteri kaldırın).

Açıklama daha sonra eklenebilir.

Test takımı (oldIE'de çalışmaz):

alert JSON.stringify f({x:e[0], y:e[1]} for e in JSON.parse "
{{1, 1}, {2, 2}, ...}
".replace(/{/g,"[").replace(/}/g,"]"))

önerilen test ortamı: http://coffeescript.org/


Ben denedim {{1, 1}, {2, 2}, {3, 3}, {1, 3}}ve [{"x" : 1, "y" : 1, "r" : 0}, {"x" : 1, "y" : 3, "r" : 0}, "x" : 2, "y" : 2, "r" : 0.78..}]doğru cevap bazı permütasyon olduğunu düşünüyorum iken döndü{{3, 3}, {1, 3}, {1, 1}}
Dr. belisarius

@belisarius, bazen yanlış gövde üreten ilkiyle eşleşen noktalarla ilgili sorun düzeltildi
John Dvorak

@belisarius lütfen bunu soruya bir test örneği olarak ekleyin.
John Dvorak

Şimdi düzgün çalışıyor gibi görünüyor :)
Dr. belisarius

1

Python, 209 205 195

from math import*
s=lambda(a,b),(c,d):atan2(d-b,c-a)
def h(l):
 r,t,p=[],pi/2,min(l)
 while 1:
    q=min(set(l)-{p},key=lambda q:(s(p,q)-t)%(2*pi));m=s(p,q);r+=[p]*(m!=t);p=q;t=m
    if p in r:return r

Hediye sarma algoritması kullanır. Sonuç en soldaki nokta ile başlar ve saat yönünün tersine sarar.

Örnek: h([(1, 1), (2, 2), (3, 3), (1, 3)])döner[(1, 3), (1, 1), (3, 3)]


printÇıktıyı almak için a ihtiyacınız yok mu?
Dr. belisarius

"Çıktı" ile işlevin çıktısı demek istedim. İşlevin sonucu döndürmek yerine yazdırmasını istiyor musunuz?
cardboard_box

the output list can be in any reasonable formatİhtiyacın yeterince açık olduğunu düşündüm . Sizce açıkça belirtilmesi gerekiyor mu?
Dr. belisarius

Kayan nokta kullanılırsa çıkış noktalarınız her zaman giriş noktalarıyla eşleşmiyor gibi görünüyor. Örneğin h([(0, 1), (0,1), (0.1 , 1)])bana verir[(0, 1), (0.10000000000000001, 1)]
Dr. belisarius
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.