En uygun Yahudi ayak tırnağı kesme algoritması nedir?


118

Ayak tırnaklarını otomatik olarak kesecek bir makine için yazılım üzerinde çalışıyorum, böylece kullanıcılar ayaklarını ısırarak veya tırnak makası kullanarak manuel olarak yapmak zorunda kalmadan kolayca ayaklarını koyabilir ve çalıştırabilir.

Potansiyel kullanıcı tabanımızın önemli bir yüzdesi muhtemelen Yahudi olacak ve belli ki ayak tırnaklarını ( veya tırnakları ) sırayla kesmeme geleneği var.

Bu geleneğin tam olarak uygulanması konusunda muhalif görüşler var gibi görünüyor, ancak aşağıdaki kuralların, dini uygulamaları sırayla ayak tırnaklarını kesmeyi yasaklayan insanları yerleştirmek için yeterli olduğunu düşünüyoruz:

  • Hiçbir bitişik ayak tırnağı arka arkaya kesilmemelidir
  • Sol ayaktaki kesme sırası, sağ ayaktaki sırayla eşleşmemelidir
  • Birbirini izleyen iki çalışmada kesme sırası aynı olmamalıdır. Sıralar kolayca tahmin edilebilir olmamalıdır, bu nedenle alternatif bir sırayı kodlamak işe yaramaz.

Ayak parmaklarını numaralandırmaya böyle karar verdik:

5 4 3 2 1  1 2 3 4 5
Left foot  Right foot

Sorunu çözmek için kod yazdım, ancak kullanılan algoritma optimalin altında: Aslında, en kötü durum performansı O (∞) . Çalışma şekli bogosort ile karşılaştırılabilir . İşte kullanılan gerçek kodun sözde kod basitleştirmesi:

function GenerateRandomSequence
   sequence = Array[5]
   foreach (item in sequence)
       item = RandomNumberBetween(1,5)
   return sequence

function GetToenailCuttingOrder
   while (true)
      sequence = GenerateRandomSequence()
      if (!AllItemsAreUnique(sequence))
         continue
      if (NoTwoAdjacentItemsHaveConsecutiveNumbers(sequence))
         return sequence

do
    leftFootSequence = GetToenailCuttingOrder()
    rightFootSequence = GetToenailCuttingOrder()
until (leftFootSequence != rightFootSequence &&
       leftFootSequence != leftFootSequenceFromLastRun &&
       rightFootSequence != rightFootSequenceFromLastRun)

Temel olarak, rastgele diziler oluşturur ve kriterleri karşılayıp karşılamadıklarını kontrol eder. Kriterleri karşılamıyorsa, baştan başlar. Gülünç derecede uzun bir zaman almaz, ancak çok öngörülemez.

Şu anda yaptığım yöntemin oldukça kötü olduğunun farkındayım, ancak daha iyi bir yol bulmakta zorlanıyorum. Herhangi biriniz daha zarif ve daha performanslı bir algoritma önerebilir mi?


28
Bu bir ev ödevi problemi gibi kokuyor. Aksi takdirde, neden diziyi sadece sabit kodlamayasınız?
Michael Brown

24
Tırnakları ısırmayı duydum ama ayak tırnaklarını?
uçar

63
Ayak tırnağı kesme makinesinin düşüncesi oldukça korkutucu. Umarım bu gerçekten bir ev ödevidir ve olmasını bekleyen acı verici bir trajedi değildir.
Peter Recore

43
Buradaki programlama zorluğu, ayak tırnaklarını kesen makineyi insanlara zarar vermeyecek şekilde kontrol etmektir. Bu sorunu çözebilecek bir programcı varsa, o kişi mutlaka bu sorunu iki dakika içinde çözebilir.
uçar

41
Yahudi geleneğiyle ilgili bir sorunun (dil) agnostik olarak etiketlenmesi hoşuma gidiyor ... :-)
Steve Melnikoff

Yanıtlar:


87

Tüm olası ayak tırnağı kesme dizilerini hiçbir kısıtlama olmaksızın oluşturabilir ve ardından Yahudi kuralını ihlal eden tüm dizileri filtreleyebilirsiniz. Neyse ki, insanların ayak başına sadece beş parmağı var *, bu yüzden sadece 5 tane var! = 120 sınırsız dizi.

Python örneği:

#seq is only valid when consecutive elements in the list differ by at least two.
def isValid(seq):
    for i in range(len(seq)-1):
        a = seq[i]
        b = seq[i+1]
        if abs(a-b) == 1:
            return False
    return True


from itertools import ifilter, permutations
validseqs = ifilter(isValid, permutations([1,2,3,4,5]))
for i in validseqs:
    print i

(1, 3, 5, 2, 4)
(1, 4, 2, 5, 3)
(2, 4, 1, 3, 5)
(2, 4, 1, 5, 3)
(2, 5, 3, 1, 4)
(3, 1, 4, 2, 5)
(3, 1, 5, 2, 4)
(3, 5, 1, 4, 2)
(3, 5, 2, 4, 1)
(4, 1, 3, 5, 2)
(4, 2, 5, 1, 3)
(4, 2, 5, 3, 1)
(5, 2, 4, 1, 3)
(5, 3, 1, 4, 2)

"Aynı sıranın tekrarı yok" kuralınızı uygulamak için yukarıdaki dizilerden sadece dördünü seçebilir ve bunları dönüşümlü olarak kullanabilirsiniz. Buradaki tek sorun, iki ayak parmağını "ardışık" olarak sayarsanız, sırasıyla 1 ile biten ve başlayan iki diziyi seçemezsiniz.

* Bir numberOfToesPerFoot değişkeni yapmak isteyebilirsiniz, böylece müşterilerinizden herhangi birinin beklediğinizden daha az veya daha fazla parmağı olduğu ortaya çıkarsa, bunu daha sonra kolayca değiştirebilirsiniz.


22
Haklısın! Polidaktili olan insanları hiç düşünmedim . Onları dışlamak yanlış olur.
Peter Olson 1411

1
daha az ayak parmağı durumu orijinal algoritma tarafından kapsanmaktadır (5 parmak için kabul edilebilir sekanslar 4 ayak parmağı için kabul edilebilir). Sorunlara neden olan o çılgın ekstra ayak parmakları;)
uçuyor

4
Çok güzel çözüm! Yine de "aynı dizinin tekrar olmaması" na biraz farklı yaklaşırdım. Makinenin en son hangi sırayı kullandığını hatırlamasını ve ardından rastgele bir tane (ama aynı değil) kullanmasını sağlayın. Bu, ikinci ayak için olduğu kadar yeni müşteriler için de işe yarar ve 4 diziye bağlı kalmaktan daha rastgele.
Jakob

3
Ayrıca, 3. ayak parmağının eksik olması gibi, ampütasyondaki eksik ayak parmakları da dikkate alınmalıdır. Bu, örneğin 3. parmağın çıkarılması artık ayak parmaklarının 2 ve 4'ün sıralı kabul edilmesine neden olursa sorunlara neden olur.
cdeszaq

2
Ya bir ayağında sadece 2 parmağı olan insanlar? Ayak tırnaklarını kesmelerine izin var mı?
matiasg

26

Gereksinimlerinizi karşılayan sınırlı sayıda dizi vardır.

  1. {1,2,3,4,5} 'in tüm permütasyonlarını oluşturun. Sadece 120 tane var.
  2. Gereksinimleri karşılamayanları reddedin ve kalan seti (kalıcı olarak) saklayın.
  3. Rastgele iki farklı sıra seçin. En son hangilerini kullandığınızı hatırlayın.

DÜZENLEME: Bu gerçekten ayak parmaklarıyla ilgili değilse, ancak setin 5'ten çok daha büyük olabileceği rastgele bir problemle ilgili ise, dizi alanı çok büyük olur ve aynı diziyi ikinci ayakta tekrarlama şansı çok az olur. Bu yüzden rastgele diziler oluşturmak ve eşleşirlerse onları reddetmek iyi bir fikirdir. "İkili veya üçlü zıpla, sonra boşlukları doldur" gibi bir kurala göre rastgele diziler oluşturmak, muhtemelen rasgele permütasyonlar ve testler oluşturmaktan daha hızlı olacaktır ve "ayak parmaklarının" sayısı büyükse örtüşme şansı yine de küçük olacaktır. .


20

Aslında, orijinal algoritmanızı en çok beğendim.

120 permütasyondan 14'ü işe yaradığından, 120'den 106'sı çalışmıyor. Yani her çekte 106/120 başarısızlık şansı vardır.

Bu, beklenen arıza sayısının:

1*(106/120) + 2*(106/120)^2 + 3*(106/120)^3 + ...

Bu sonsuz seriyi özetlemek çok zor değil:

S       = 1*x + 2*x^2 + 3*x^3 + ...

X ile çarpın:

x*S     =       1*x^2 + 2*x^3 + ...

Çıkar:

S - x*S = x + x^2 + x^3 + ...

Tekrar x ile çarpın ve tekrar çıkarın:

x*S - x^2*S = x^2 + x^3 + ...
S - 2*x*S + x^2S = x
S*(1-x)^2 = x
S = x/(1-x)^2

X = 106/120 olduğundan, S = 64.9.

Yani, ortalama olarak döngünüzün bir çözüm bulmak için yalnızca 65 yinelemeye ihtiyacı vardır .

Örneğin bin yineleme alma olasılığı nedir?

Tek bir yinelemede başarısız olma olasılığı 104/120, yani 1000 yinelemede başarısız olma olasılığı (104/120) ^ 1000, bu da 10 ^ (- 63) gibi bir şey. Yani, hayatınız boyunca ve muhtemelen evrenin yaşamı boyunca bunun gerçekleştiğini asla göremeyeceksiniz.

Önceden hesaplanmış tablo yok, farklı sayıdaki parmaklara / ayak parmaklarına / ellere / ayaklara kolay adaptasyon, farklı kural setlerine kolay adaptasyon ... Neyi sevmemek? Üstel bozulma harika bir şeydir.

[Güncelleme]

Hay aksi, orijinal formülü yanlış anladım ... Olasılıklarımın toplamı 1 olmadığı için :-)

Beklenen arıza sayısı için doğru ifade şudur:

0*(14/120) + 1*(106/120)*(14/120) + 2*(106/120)^2*(14/120) + ...

(Örneğin, tam olarak iki başarısızlık elde etmek için, iki başarısızlık ve ardından bir başarı gerekir . İki başarısızlık olasılığı (106/120) ^ 2; bir başarının olasılığı (14/120); "2" terimi.)

Yani benim S'm (1-x) çarpanıyla (yani, 14/120) kapalı. Gerçek beklenen arıza sayısı yalnızca x / (1-x) = 106/14 = 7.57'dir. Dolayısıyla bir çözüm bulmak için ortalama olarak yalnızca 8-9 yineleme gerekir (7,5 başarısızlık artı bir başarı).

"1000 başarısızlık" durumu için matematiğim hala doğru, sanırım.


1
Kutunun dışında düşünmek ve soruna farklı bir bakış açısı vermek için +1.
nalply

9

Açık olan: Çalışan bir sipariş bulun ve onu sabit bir şekilde kodlayın. Ama bunu yapmak isteyeceğini sanmıyorum.

Permütasyonları, yaptığınız yoldan çok daha iyi üretebilirsiniz. Ret örneklemesi yapmanıza gerek yok. Başlangıçta sıralanmış permütasyonda (1, 2, .. 5) bir Fisher Yates karıştırması kullanın ve rastgele bir permütasyona sahip olacaksınız. http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle

Ancak genel olarak, başarılı bir giriş oluşturma olasılığı yeterince yüksek olduğu sürece üretme ve test etme yöntemi bana tamamen iyi görünüyor. Kriterlerinize göre pek çok geçerli sıralama olduğundan eminim, rastgele bir permütasyona geçtiğinizde, birçok reddetme yinelemesi yapmanız gerekeceğinden şüpheliyim.


2

Burada gerçekten yeni bir şey yok, aynı çözüm @ Kevin zaten yayınlandı, ancak bunun işlevsel bir dile nasıl çevrildiğini görmek ilginç bence. Bu durumda Mathematica :

Extract[#,Position[Times @@ (Abs@#-1)&/@ Differences/@ #, Except@0, 1][[2 ;;]]]  
         &@ Permutations@Range@5

Bazı açıklamalar:

Permutations@Range@5 Calculates all permutations of {1, 2, 3, 4, 5}

Differences          Calculate the differences between adjacent elements
                     (we wish to discard all lists containing +1 or -1)

Times @@ (Abs@#-1)   Abs turns the -1s into +1s, and then to zeros by subtracting
                     one, then TIMES multiplies all elements, giving zero when 
                     the original result of "Differences" contained a +1 or a -1

Position ... Except@0 Returns the position of the non zero results

Extract              Returns the original elements according to the calculated 
                     positions

Nihai sonuç şudur:

{{1, 3, 5, 2, 4}, {1, 4, 2, 5, 3}, {2, 4, 1, 3, 5}, {2, 4, 1, 5, 3}, 
 {2, 5, 3, 1, 4}, {3, 1, 4, 2, 5}, {3, 1, 5, 2, 4}, {3, 5, 1, 4, 2}, 
 {3, 5, 2, 4, 1}, {4, 1, 3, 5, 2}, {4, 2, 5, 1, 3}, {4, 2, 5, 3, 1}, 
 {5, 2, 4, 1, 3}, {5, 3, 1, 4, 2}}

Düzenle

Veya açıklaması daha zor ama daha kısa:

Reap[ Table[ If[Times @@ (Abs@Differences@i - 1) != 0, Sow@i],
           {i, Permutations@Range@5}]][[2, 1]]

0

Bu probleme rastgelelik katmak için gerçekten hiçbir neden yok. Bu sorunu karşılayan yalnızca 14 sekans vardır ve bu sekansların bazılarının sıralanması, yerleştirmeye çalıştığınız estetik duyguyu en iyi şekilde tatmin edecektir. Bu nedenle, bu problemi, muhtemelen önceden belirlenmiş bir sırayla, bu 14 arasından bir dizi seçmek için bir algoritmaya indirgemelisiniz.

14'ü bulmak için algoritmanın Javascript uygulaması:

function swap (a, i, j) {
  var temp = a[i]
  a[i]=a[j]
  a[j]=temp
}

function permute (b, n, a) {
  if (n==4) {
    b.push(a.slice(0)) //copy array
  }
  else {
    for (var i = n; i < 5; i++) {
      swap(a,n,i)
      permute(b, n+1, a)
      swap(a,n,i)
    }
  }
}

var a = [1,2,3,4,5]
var b = []
var c = []

permute(b,0,a)

for (var i = 1; i < b.length-1; i++) {
  var good = true
  for (var j = 0; j < b[i].length; j++) {
    if (Math.abs(b[i][j-1]-b[i][j]) < 2 || Math.abs(b[i][j]-b[i][j+1]) < 2) {
      good = false
    }
  }
  if (good) c.push(b[i].join(''))
}

console.log(c)

DÜZENLEME: Dizilerin rastgele oluşturulması gerektiğine dair yeni gereksinim kolayca karşılanamaz. Muhtemelen yapabileceğiniz en iyi şey, onları sözde rastgele oluşturmaktır; bu, onları önceden sabit kodlamak kadar belirleyicidir ve bu nedenle kimsenin batıl inançlarını tatmin etmemelidir.

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.