ขั้นตอนวิธีการตัดเล็บเท้าของชาวยิวที่ดีที่สุดคืออะไร?


118

ฉันกำลังทำงานกับซอฟต์แวร์สำหรับเครื่องที่จะตัดเล็บเท้าโดยอัตโนมัติเพื่อให้ผู้ใช้สามารถสอดเท้าเข้าไปแล้ววิ่งได้แทนที่จะต้องทำด้วยตนเองโดยการกัดหรือใช้กรรไกรตัดเล็บ

ฐานผู้ใช้ที่มีศักยภาพของเราจำนวนมากน่าจะเป็นชาวยิวและเห็นได้ชัดว่ามีประเพณีเกี่ยวกับการไม่ตัดเล็บเท้า ( หรือเล็บมือ ) ตามลำดับ

ดูเหมือนจะมีความเห็นที่ไม่เห็นด้วยกับการนำประเพณีนี้ไปใช้อย่างถูกต้อง แต่เราคิดว่ากฎต่อไปนี้เพียงพอที่จะรองรับผู้ที่ปฏิบัติทางศาสนาห้ามไม่ให้ตัดเล็บเท้าตามลำดับ:

  • ไม่ควรตัดเล็บเท้า 2 ข้างติดกัน
  • ลำดับการตัดที่เท้าซ้ายไม่ควรตรงกับลำดับที่เท้าขวา
  • ลำดับการตัดของการวิ่งสองครั้งติดต่อกันไม่ควรเหมือนกัน ลำดับไม่ควรคาดเดาได้ง่ายดังนั้นการเข้ารหัสลำดับแบบสลับจึงไม่ทำงาน

นี่คือวิธีที่เราตัดสินใจที่จะนับนิ้วเท้า:

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

ฉันได้เขียนรหัสในการแก้ปัญหา แต่อัลกอริทึมที่ใช้ย่อยที่ดีที่สุด: ในความเป็นจริงการปฏิบัติงานในกรณีที่เลวร้ายที่สุดคือO (∞) วิธีการทำงานก็เปรียบได้กับbogosort นี่คือการลดความซับซ้อนของรหัสเทียมของรหัสจริงที่ใช้:

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)

โดยทั่วไปจะสร้างลำดับแบบสุ่มและตรวจสอบว่าตรงตามเกณฑ์หรือไม่ หากไม่เป็นไปตามเกณฑ์ก็เริ่มต้นใหม่ ใช้เวลาไม่นานอย่างน่าขัน แต่ก็ไม่สามารถคาดเดาได้

ฉันรู้ว่าวิธีที่ฉันทำอยู่ตอนนี้มันค่อนข้างแย่ แต่ฉันมีปัญหาในการหาวิธีที่ดีกว่านี้ มีใครช่วยแนะนำอัลกอริทึมที่สวยงามและมีประสิทธิภาพมากขึ้นได้ไหม


28
นี่กลิ่นเหมือนปัญหาการบ้าน ไม่งั้นทำไมไม่ฮาร์ดโค้ดลำดับล่ะ
Michael Brown

24
ฉันเคยได้ยินเรื่องการกัดเล็บ แต่เล็บเท้า?
บิน

63
ความคิดของเครื่องตัดเล็บเท้านั้นค่อนข้างน่ากลัว ฉันหวังว่านี่จะเป็นการบ้านและไม่ใช่โศกนาฏกรรมอันเจ็บปวดที่รอให้เกิดขึ้น
Peter Recore

43
ความท้าทายในการเขียนโปรแกรมที่นี่คือการควบคุมเครื่องจักรที่ตัดเล็บเท้าเพื่อไม่ให้ทำร้ายผู้คน หากมีโปรแกรมเมอร์ที่สามารถแก้ปัญหานั้นได้แน่นอนว่าบุคคลนั้นสามารถแก้ปัญหานี้ได้ภายในสองนาที
บิน

41
ฉันชอบความจริงที่ว่าคำถามเกี่ยวกับประเพณีของชาวยิวถูกแท็กเป็น (ภาษา) ไม่เชื่อเรื่องพระเจ้า ... :-)
Steve Melnikoff

คำตอบ:


87

คุณสามารถสร้างลำดับการตัดเล็บเท้าที่เป็นไปได้ทั้งหมดโดยไม่มีข้อ จำกัด จากนั้นกรองลำดับทั้งหมดที่ละเมิดกฎของชาวยิว โชคดีที่มนุษย์มีนิ้วเท้าเพียง 5 นิ้วต่อเท้า * ดังนั้นจึงมีเพียง 5 นิ้วเท่านั้น! = 120 ลำดับที่ไม่ จำกัด

ตัวอย่าง Python:

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

ในการบังคับใช้กฎ "ไม่ซ้ำในลำดับเดียวกัน" ของคุณคุณสามารถเลือกสี่ลำดับข้างต้นและใช้สลับกันได้ สิ่งเดียวที่จับได้คือถ้าคุณนับนิ้วเท้าใหญ่ทั้งสองเป็น "ต่อเนื่องกัน" คุณจะไม่สามารถเลือกสองลำดับที่ลงท้ายและเริ่มต้นด้วย 1 ตามลำดับ

* คุณอาจต้องการสร้างตัวแปร numberOfToesPerFoot เพื่อให้คุณสามารถเปลี่ยนได้อย่างง่ายดายในภายหลังหากลูกค้าของคุณมีนิ้วเท้าน้อยกว่าที่คุณคาดไว้หรือมากกว่านั้น


22
คุณถูก! ฉันไม่เคยคิดว่าแม้คนที่มีpolydactly การยกเว้นพวกเขาจะเป็นเรื่องผิด
Peter Olson

1
อัลกอริทึมเดิมจะครอบคลุมกรณีนิ้วเท้าน้อยลง (ลำดับที่ยอมรับได้สำหรับ 5 นิ้วเท้าเป็นที่ยอมรับสำหรับ 4 นิ้ว) มันเป็นนิ้วเท้าพิเศษที่ทำให้เกิดปัญหา;)
บิน

4
ทางออกที่ดีมาก! ฉันจะเข้าใกล้ "ไม่ซ้ำในลำดับเดียวกัน" แตกต่างกันเล็กน้อย เพียงแค่ทำให้เครื่องจำลำดับที่ใช้สุดท้ายและใช้ลำดับสุ่ม (แต่ไม่ใช่ลำดับเดียวกัน) ถัดไป ซึ่งใช้ได้กับเท้าที่สองเช่นเดียวกับไคลเอนต์ใหม่และเป็นแบบสุ่มมากกว่าการยึดติดกับ 4 ลำดับ
Jakob

3
นอกจากนี้คุณยังต้องพิจารณานิ้วเท้าที่หายไปจากการตัดขาเช่นนิ้วหัวแม่เท้าที่ 3 หายไป สิ่งนี้ทำให้เกิดปัญหาเช่นหากการถอดนิ้วเท้าที่ 3 ออกทำให้นิ้วเท้าที่ 2 และ 4 ถูกพิจารณาตามลำดับ
cdeszaq

2
แล้วคนที่มีเพียง 2 นิ้วเท้าข้างเดียวล่ะ? อนุญาตให้ตัดเล็บเท้าได้หรือไม่?
matiasg

26

มีลำดับจำนวน จำกัด ที่ตรงตามความต้องการของคุณ

  1. สร้างการเรียงสับเปลี่ยนทั้งหมดของ {1,2,3,4,5} มีแค่ 120.
  2. ปฏิเสธชุดที่ไม่ตรงตามข้อกำหนดและจัดเก็บชุดที่เหลือ (ถาวร)
  3. สุ่มเลือกสองลำดับที่แตกต่างกัน จำรายการที่คุณใช้ครั้งล่าสุด

แก้ไข: หากสิ่งนี้ไม่ได้เกี่ยวกับนิ้วเท้า แต่เกี่ยวกับปัญหาสุ่มบางอย่างที่เซตสามารถมีขนาดใหญ่กว่า 5 ได้พื้นที่ลำดับจะมีขนาดใหญ่มากและโอกาสที่จะทำซ้ำลำดับเดียวกันบนเท้าที่สองจะน้อยมาก ดังนั้นการสร้างลำดับแบบสุ่มและปฏิเสธหากตรงกันเป็นความคิดที่ดี การสร้างลำดับแบบสุ่มตามกฎบางข้อเช่น "กระโดดทีละสองสามหรือสามแล้วเติมช่องว่าง" อาจเร็วกว่าการสร้างการเรียงสับเปลี่ยนและการทดสอบแบบสุ่มและโอกาสที่จะทับซ้อนกันจะยังน้อยหากจำนวน "นิ้วเท้า" มีมาก .


20

อันที่จริงฉันชอบอัลกอริทึมดั้งเดิมของคุณที่สุด

เนื่องจากการเรียงสับเปลี่ยน 14 จาก 120 การทำงาน 106 จาก 120 จึงไม่ทำ ดังนั้นการตรวจสอบแต่ละครั้งจึงมีโอกาสล้มเหลว 106/120

นั่นหมายความว่าจำนวนความล้มเหลวที่คาดไว้คือ:

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

ไม่ยากเกินไปที่จะสรุปซีรี่ส์ที่ไม่มีที่สิ้นสุดนี้:

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

คูณด้วย x:

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

ลบ:

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

คูณด้วย x อีกครั้งแล้วลบอีกครั้ง:

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, S = 64.9

ดังนั้นโดยเฉลี่ยแล้วลูปของคุณต้องการการวนซ้ำเพียง 65 ครั้งเพื่อหาวิธีแก้ปัญหา

ความน่าจะเป็นที่จะเกิดขึ้นกล่าวคือการวนซ้ำหนึ่งพันครั้งคืออะไร?

ความน่าจะเป็นที่จะล้มเหลวในการทำซ้ำครั้งเดียวคือ 104/120 ดังนั้นความน่าจะเป็นของการทำซ้ำ 1,000 ครั้งคือ (104/120) ^ 1000 ซึ่งเหมือนกับ 10 ^ (- 63) นั่นคือคุณจะไม่เคยเห็นมันเกิดขึ้นในชีวิตของคุณและอาจจะไม่มีในช่วงชีวิตของจักรวาล

ไม่มีตารางที่คำนวณไว้ล่วงหน้าปรับให้เข้ากับจำนวนนิ้ว / นิ้วเท้า / มือ / เท้าที่แตกต่างกันได้ง่ายปรับให้เข้ากับกฎต่างๆได้ง่าย ... จะไม่ชอบอะไร? การสลายตัวแบบเอกซ์โปเนนเชียลเป็นสิ่งที่ยอดเยี่ยม

[อัพเดต]

อ๊ะฉันทำผิดสูตรดั้งเดิม ... เนื่องจากความน่าจะเป็นของฉันไม่รวมเป็น 1 :-)

นิพจน์ที่ถูกต้องสำหรับจำนวนความล้มเหลวที่คาดไว้คือ:

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

(ตัวอย่างเช่นเพื่อให้ได้ความล้มเหลวสองครั้งคุณต้องมีความล้มเหลวสองครั้งตามด้วยความสำเร็จความล้มเหลวสองครั้งมีความน่าจะเป็น (106/120) ^ 2 ความสำเร็จหนึ่งมีความน่าจะเป็น (14/120) คูณด้วยกันเพื่อให้ได้น้ำหนัก "2" เทอม)

ดังนั้น S ของฉันจึงปิดด้วยตัวประกอบของ (1-x) (เช่น 14/120) จำนวนความล้มเหลวที่คาดไว้จริงเป็นเพียง x / (1-x) = 106/14 = 7.57 ดังนั้นโดยเฉลี่ยแล้วการทำซ้ำจะใช้เวลาเพียง 8-9 ครั้งเพื่อหาทางแก้ไข (7.5 ความล้มเหลวบวกความสำเร็จหนึ่งครั้ง)

ฉันคิดว่าคณิตศาสตร์ของฉันสำหรับกรณี "1,000 ความล้มเหลว" ยังคงถูกต้อง


1
+1 สำหรับการคิดนอกกรอบและให้วิธีการมองปัญหาที่แตกต่างออกไป
nalply

9

สิ่งที่ชัดเจน: ค้นหาหนึ่งคำสั่งที่ใช้งานได้และกำหนดรหัสให้ยาก แต่ฉันไม่คิดว่าคุณต้องการทำเช่นนั้น

คุณสามารถสร้างการเรียงสับเปลี่ยนได้ดีกว่าวิธีที่คุณทำ คุณไม่จำเป็นต้องทำการสุ่มตัวอย่างการปฏิเสธ ใช้ฟิชเชอร์เยตส์สับเปลี่ยนในการเรียงลำดับขั้นต้น (1, 2, .. 5) และคุณจะมีการเรียงสับเปลี่ยนแบบสุ่ม http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle

แต่โดยทั่วไปแล้ววิธีการสร้างและทดสอบดูเหมือนจะดีสำหรับฉันโดยสิ้นเชิงตราบใดที่ความน่าจะเป็นในการสร้างรายการที่ประสบความสำเร็จนั้นสูงพอ ฉันแน่ใจว่ามีลำดับที่ถูกต้องตามเกณฑ์ของคุณเมื่อคุณเปลี่ยนไปใช้การเปลี่ยนแปลงแบบสุ่มฉันสงสัยว่าคุณจะต้องทำซ้ำการปฏิเสธหลายครั้ง


2

ไม่มีอะไรใหม่จริงๆที่นี่โซลูชันเดียวกันที่ @Kevin โพสต์ไว้แล้ว แต่ฉันคิดว่าน่าสนใจที่จะดูว่ามันแปลเป็นภาษาที่ใช้งานได้อย่างไร ในกรณีนี้Mathematica :

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

คำอธิบายบางส่วน:

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

ผลลัพธ์สุดท้ายคือ:

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

แก้ไข

หรืออธิบายยากกว่า แต่สั้นกว่า:

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

0

ไม่มีเหตุผลที่จะนำการสุ่มเข้ามาในปัญหานี้ มีเพียง 14 ลำดับที่ตอบสนองปัญหานี้และแน่นอนว่าลำดับบางส่วนของลำดับเหล่านั้นจะตอบสนองความรู้สึกทางสุนทรียะที่คุณพยายามจะรองรับได้ดีที่สุด ดังนั้นคุณควรลดปัญหานี้เป็นอัลกอริทึมสำหรับการเลือกลำดับจาก 14 เหล่านั้นซึ่งอาจเป็นลำดับที่ตั้งไว้ล่วงหน้า

การใช้อัลกอริทึม Javascript เพื่อค้นหา 14:

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)

แก้ไข:ข้อกำหนดใหม่ที่ต้องสร้างลำดับต้องถูกสร้างขึ้นแบบสุ่มไม่สามารถทำได้โดยง่าย สิ่งที่ดีที่สุดที่คุณสามารถทำได้คือการสร้างพวกมันหลอกๆซึ่งเป็นปัจจัยที่กำหนดได้เช่นเดียวกับการเข้ารหัสอย่างยากลำบากล่วงหน้าและไม่ควรตอบสนองความเชื่อโชคลางของใครก็ตาม

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.