最佳的犹太趾甲切割算法是什么?


118

我正在为会自动修剪脚趾甲的机器开发软件,以便用户可以简单地将脚放进去并运行它,而不必通过咬伤或使用指甲钳手动进行操作。

我们潜在用户群中有很大一部分可能是犹太人,而且很明显,有一种传统是不按顺序修剪脚趾甲或指甲

对于这种传统的确切应用,似乎存在不同意见,但是我们认为以下规则足以容纳宗教信仰禁止按趾甲切割的人:

  • 不应连续切割两个相邻的脚趾甲
  • 左脚的切割顺序应与右脚的切割顺序不匹配
  • 连续两次切割的切割顺序不应相同。序列不应该容易预测,因此对交替序列进行硬编码是行不通的。

这就是我们决定给脚趾编号的方式:

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
这闻起来像是作业问题。否则,为什么不对序列进行硬编码?
迈克尔·布朗

24
我听说过咬指甲,但是脚趾甲?
飞行

63
脚趾甲切割机的想法非常令人恐惧。我希望这确实是家庭作业,而不是痛苦的悲剧等待发生。
Peter Recore 2011年

43
这里的编程挑战是控制切趾甲的机器,以免伤人。如果有一个能够解决该问题的程序员,那么那个人肯定可以在两分钟内解决这个问题。
飞行

41
我喜欢这样一个事实,一个关于犹太传统的问题被标记为(语言)不可知的……:-)
Steve Melnikoff 2011年

Answers:


87

您可以无限制地生成所有可能的趾甲切割序列,然后过滤掉所有违反犹太规则的序列。幸运的是,人类每英尺只有五个脚趾*,所以只有五个脚趾!= 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
你是对的!我什至从未考虑过具有多面性的人。排除它们是错误的。
彼得·奥尔森

1
原始算法覆盖的脚趾越少(5个脚趾的可接受序列对于4个脚趾而言可接受)。正是这些疯狂的多余脚趾引起了问题;)
飞过

4
非常好的解决方案!但是,我会处理“没有相同序列的重复”的方法,但略有不同。只需让机器记住上次使用的顺序,然后再使用一个随机顺序(但不相同)即可。它适用于第二只脚和新客户,并且比坚持4个序列更随机。
雅各布

3
人们还需要考虑截肢导致的脚趾缺失,例如第三脚趾缺失。例如,如果现在移除第三个脚趾导致脚趾2和4被认为是连续的,则这会引起问题。
cdeszaq 2012年

2
一只脚只有两个脚趾的人呢?他们可以剪脚趾甲吗?
matiasg 2014年

26

有一定数量的序列可以满足您的要求。

  1. 生成{1,2,3,4,5}的所有排列。只有120个
  2. 拒绝那些不满足要求的内容,并永久存储剩余的内容。
  3. 随机选择两个不同的序列。记住上次使用的是哪个。

编辑:如果这不是真的关于脚趾,而是关于集合可能大于5的一些随机问题,则序列空间将变得很大,并且在第二只脚上重复相同序列的机会会变得非常小。因此,随机生成序列并在匹配时拒绝它们是一个好主意。根据诸如“三三两跳,然后填空”之类的规则生成随机序列可能比生成随机排列和测试更快,并且如果“脚趾”的数量很大,重叠的机会仍然很小。 。


20

实际上,我最喜欢您的原始算法。

由于120个排列中的14个起作用,因此120个排列中的106个不起作用。因此,每张支票都有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,因此失败1000次迭代的概率为(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次失败加上一次成功)。

我认为关于“ 1000个失败”案例的数学仍然是正确的。


1
+1可让您跳出框框思考,并给出解决问题的另一种方式。
2011年

9

显而易见的是:找到一个有效的命令,并对其进行硬编码。但我不认为您要这样做。

您可以比执行方式更好地生成排列。您不需要进行拒绝采样。对初始排序的排列(1、2,.. 5)使用Fisher Yates随机播放,您将获得随机排列。 http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle

但是总的来说,只要生成成功条目的可能性足够高,那么generate and test方法对我来说似乎就完全可以了。我确信根据您的标准,会有许多有效序列,一旦切换到随机排列,我怀疑您将必须进行许多拒绝迭代。


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个序列中以预定顺序选择序列。

找到14个算法的Javascript实现:

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)

编辑:序列必须随机生成的新要求不能轻易满足。您可能要做的最好的事情就是伪随机地生成它们,就像确定性地将它们预先硬编码一样,因此不应满足任何人的迷信。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.