简单的递归问题

时间:2009-03-20 20:27:37

标签: ruby recursion coin-flipping

我正在迈出递归和动态编程的第一步,并且有一个关于形成子问题来建模递归的问题。

问题:

  

有多少种不同的方式   翻转一个公平的硬币5次而没有   连续三个或更多头?

如果有人可以提供一些评论很多的代码(Ruby首选但不是必需的)来帮助我实现目标。如果重要的话,我不是学生,这是对Project Euler问题的修改,使我很容易理解。我只需要编写递归公式。

如果您想将问题抽象为有多少种不同的方式来翻转一枚硬币Y次并且没有连续Z或更多的头,这也可能是有益的。再次感谢,这个网站摇滚。

6 个答案:

答案 0 :(得分:6)

您只需为此创建一个公式:

在没有连续3个头的情况下翻转硬币5次的方法的数量等于5个硬币翻转的组合的数量减去连续至少三个头的组合的数量。在这种情况下:

HHH-- (4 combinations)
THHH- (2 combinations)
TTHHH (1 combination)

组合总数= 2 ^ 5 = 32.而32 - 7 = 25。

如果我们连续N次掷硬币N次,则总量为2 ^ N且至少Q头的量为2 ^(N-Q + 1)-1。所以一般的答案是:

Flip(N,Q) = 2^N - 2^(N-Q+1) +1

当然,你可以使用递归来模拟总量:

flipme: N x N -> N
flipme(flipsleft, maxhead) = flip(flipsleft, maxhead, 0)

flip: N x N x N -> N
flip(flipsleft, maxhead, headcount) ==
  if flipsleft <= 0 then 0
  else if maxhead<=headcount then 0
  else 
    flip(flipsleft - 1, maxhead, headcount+1) + // head
    flip(flipsleft - 1, maxhead, maxhead)       // tail  

答案 1 :(得分:1)

这不是采用所有可能的5位序列并去除有三个连续1位的情况(假设1 =头,0 =尾)?

答案 2 :(得分:1)

这是我在Ruby中的解决方案

def combination(length=5)
  return [[]] if length == 0
  combination(length-1).collect {|c| [:h] + c if c[0..1]!= [:h,:h]}.compact +
  combination(length-1).collect {|c| [:t] + c }
end

puts "There are #{combination.length} ways"

所有递归方法都以最后一个案例的早期开始。

return [[]] if length == 0

这将返回一个组合数组,其中唯一的零长度组合是[]

下一位(简化)是......

combination(length-1).collect {|c| [:h] + c } +
combination(length-1).collect {|c| [:t] + c }

所以..这说..我想要一个比所需长度短的所有组合,其中:head添加到每个组合中......加上所有组合都是一个较短的尾部添加到它们。

考虑递归的方法是......“假设我有一个方法来做n-1案例......我需要添加什么才能使它覆盖n个案例”。对我而言,感觉就像感应一样。

此代码将生成头部和尾部的所有组合,直到给定的长度。

我们不希望有:h:h:h。这只能发生在我们:h:h并且我们添加:h。所以......我在添加:h时放了一个if c[0..1] != [:h,:h],因此当它即将构成无效组合时,它将返回nil而不是数组。

然后我必须compact结果忽略所有仅nil的结果

答案 3 :(得分:0)

这分解为:

当第一次翻转是头部+第一次翻转是尾巴时,有多少种方法可以翻转一枚硬币四次:

所以在python中:

HEADS = "1"
TAILS = "0"

def threeOrMoreHeadsInARow(bits):
    return "111" in bits

def flip(n = 5, flips = ""):
   if threeOrMoreHeadsInARow(flips):
      return 0
   if n == 0:
      return 1
   return flip(n - 1, flips + HEADS) + flip(n - 1, flips + TAILS)

答案 4 :(得分:0)

这是在Python中实现它的一种方法:

#This will hold all possible combinations of flipping the coins. 
flips = [[]]
for i in range(5):
    #Loop through the existing permutations, and add either 'h' or 't' 
    #to the end. 
    for j in range(len(flips)):
        f = flips[j]
        tails = list(f)
        tails.append('t')
        flips.append(tails)
        f.append('h')

#Now count how many of the permutations match our criteria.
fewEnoughHeadsCount = 0
for flip in flips:
    hCount = 0
    hasTooManyHeads = False
    for c in flip:
        if c == 'h': hCount += 1
        else: hCount = 0
        if hCount >= 3: hasTooManyHeads = True
    if not hasTooManyHeads: fewEnoughHeadsCount += 1

print 'There are %s ways.' % fewEnoughHeadsCount

答案 5 :(得分:0)

这是一个使用Ruby yield语句的递归组合函数:

def combinations(values, n)
  if n.zero?
    yield []
  else
    combinations(values, n - 1) do |combo_tail|
      values.each do |value|
        yield [value] + combo_tail
      end
    end
  end
end

你可以使用正则表达式连续解析三个头:

def three_heads_in_a_row(s)
  ([/hhh../, /.hhh./, /..hhh/].collect {|pat| pat.match(s)}).any?
end

最后,你会得到这样的答案:

total_count = 0
filter_count = 0

combinations(["h", "t"], 5) do |combo|
  count += 1
  unless three_heads_in_a_row(combo.join)
      filter_count += 1
  end
end

puts "TOTAL: #{ total_count }"
puts "FILTERED: #{ filter_count }"

这就是我如何做到的:)