views:

920

answers:

6

I'm taking my first steps into recursion and dynamic programming and have a question about forming subproblems to model the recursion.

Problem:

How many different ways are there to flip a fair coin 5 times and not have three or more heads in a row?

If some could put up some heavily commented code (Ruby preferred but not essential) to help me get there. I am not a student if that matters, this is a modification of a Project Euler problem to make it very simple for me to grasp. I just need to get the hang of writing recursion formulas.

If you would like to abstract the problem into how many different ways are there to flip a fair coin Y times and not have Z or more heads in a row, that may be beneficial as well. Thanks again, this website rocks.

+1  A: 

Isn't this a matter of taking all possible 5 bit sequences and removing the cases where there are three sequential 1 bits (assuming 1 = heads, 0 = tails)?

plinth
Yes, but by using recursion, I would be able to code up a problem like how many different ways are there to flip a fair coin 10^10 times and not have 534 or more heads in a row. If I don't use recursion, then I am left going through the every combination ...
Auburnate
Hmm, I don't think you have a good grasp of what recursion means - it certainly doesn't mean "magic".
anon
A: 

This breaks down to:

How many ways are there to flip a fair coin four times when the first flip was heads + when the first flip was tails:

So in 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)
Aaron Maenpaa
+6  A: 

You can simply create a formula for that:

The number of ways to flip a coin 5 times without having 3 heads in a row is equal to the number of combinations of 5 coin flips minus the combinations with at least three heads in a row. In this case:

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

The total number of combinations = 2^5 = 32. And 32 - 7 = 25.

If we flip a coin N times without Q heads in a row, the total amount is 2^N and the amount with at least Q heads is 2^(N-Q+1)-1. So the general answer is:

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

Of course you can use recursion to simulate the total amount:

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
Gamecat
HTHHH adds one more combination
Austin Salonen
Thanks, you are right!
Gamecat
A: 

Here's one way to do it in 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
RossFabricant
A: 

Here's a recursive combination function using Ruby yield statements:

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

And you could use regular expressions to parse out three heads in a row:

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

Finally, you would get the answer using something like this:

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

So that's how I would do it :)

zvoase
+1  A: 

Here's my solution in 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"

All recursive methods start with an early out for the end case.

return [[]] if length == 0

This returns an array of combinations, where the only combination of zero length is []

The next bit (simplified) is...

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

So.. this says.. I want all combinations that are one shorter than the desired length with a :head added to each of them... plus all the combinations that are one shorter with a tail added to them.

The way to think about recursion is.. "assuming I had a method to do the n-1 case.. what would I have to add to make it cover the n case". To me it feels like proof by induction.

This code would generate all combinations of heads and tails up to the given length.

We don't want ones that have :h :h :h. That can only happen where we have :h :h and we are adding a :h. So... I put an if c[0..1] != [:h,:h] on the adding of the :h so it will return nil instead of an array when it was about to make an invalid combination.

I then had to compact the result to ignore all results that are just nil

Nigel Thorne
Thanks and great explanation.
Auburnate