0

Hi I have a question on an existing algo problem.

Existing problem description: Generate 10-digit number using a phone keypad

1 2 3
4 5 6
7 8 9
  0
Community
  • 1
  • 1
bjackfly
  • 3,236
  • 2
  • 25
  • 38
  • If the recursive function that solves the original problem has function signature `int count(int n)` then the solution to the new problem has function signature `pair count2( int n, int e=0 )` where you keep track of the number of even digits in the sequence via `e`, and return both `n` and `e` in the return value. If at any point `e>3` then return `n=0`. – Matt Sep 21 '13 at 00:16
  • 1
    @Matt: Why would you return `e`? It's not necessarily the same for all sequences. And what happened to the "ending position" argument? – Ben Voigt Sep 21 '13 at 00:24
  • @BenVoigt Yeah you're right. See my answer instead. – Matt Sep 21 '13 at 00:59
  • What is your question? Could you make this complete, so that we don't have to follow the link to figure out what you're asking? – Teepeemm Sep 27 '13 at 00:10

1 Answers1

2

Though this question has a tag of C++, consider this pseudo-code to express the algorithm (which conveniently happens to be written in ruby.)

# Where the knight can jump to
$m = {
  0 => [4,6], 1 => [6,8], 2 => [7,9], 3 => [4,8], 4 => [0,3,9],
  5 => [], 6 => [0,1,7], 7 => [2,6], 8 => [1,3], 9 => [2,4]
}

$cache = Hash.new
# return count
def nseq( k, n, e=0 )
  e += 1 if k.even?
  return 0 if 3 < e
  return 1 if n == 1
  key = "#{k}:#{n}:#{e}" # for the memoization
  return $cache[key] if $cache.has_key? key
  # Sum nseq(j,n-1,e) for j in $m[k]
  return $cache[key] = $m[k].inject(0) { |sum,j| sum + nseq( j, n-1, e ) }
end

0.upto(9) do |k|
  2.upto(8) do |n|
    count = nseq(k,n)
    puts "k=#{k},n=#{n}: #{count}"
    break if count.zero?
  end
end

This outputs

k=0,n=2: 2
k=0,n=3: 6
k=0,n=4: 8
k=0,n=5: 16
k=0,n=6: 0
k=1,n=2: 2
k=1,n=3: 5
k=1,n=4: 10
k=1,n=5: 24
k=1,n=6: 32
k=1,n=7: 64
k=1,n=8: 0
k=2,n=2: 2
k=2,n=3: 4
k=2,n=4: 10
k=2,n=5: 16
k=2,n=6: 32
k=2,n=7: 0
k=3,n=2: 2
k=3,n=3: 5
k=3,n=4: 10
k=3,n=5: 24
k=3,n=6: 32
k=3,n=7: 64
k=3,n=8: 0
k=4,n=2: 3
k=4,n=3: 6
k=4,n=4: 14
k=4,n=5: 16
k=4,n=6: 32
k=4,n=7: 0
k=5,n=2: 0
k=6,n=2: 3
k=6,n=3: 6
k=6,n=4: 14
k=6,n=5: 16
k=6,n=6: 32
k=6,n=7: 0
k=7,n=2: 2
k=7,n=3: 5
k=7,n=4: 10
k=7,n=5: 24
k=7,n=6: 32
k=7,n=7: 64
k=7,n=8: 0
k=8,n=2: 2
k=8,n=3: 4
k=8,n=4: 10
k=8,n=5: 16
k=8,n=6: 32
k=8,n=7: 0
k=9,n=2: 2
k=9,n=3: 5
k=9,n=4: 10
k=9,n=5: 24
k=9,n=6: 32
k=9,n=7: 64
k=9,n=8: 0

The result is the number of all n-length sequences starting on key k, which have no more than 3 even digits in them. For example, the last entry is k=9,n=8: 0. This means that all sequences of length 8 starting on key 9 include more than 3 even digits.

EDIT: Here it is translated into C++. It produces identical output as above.

#include<iostream>
#include<map>
using namespace std;

const int MAX_EVENS = 3; // Assume < 8

// Where the knight can jump to
const int jumpto[][3] = { {4,6}, // 0
  {6,8}, {7,9}, {4,8},   // 1 2 3
  {0,3,9}, {}, {0,1,7},  // 4 5 6
  {2,6}, {1,3}, {2,4} }; // 7 8 9
const int jumpto_size[] = { 2, // 0
  2, 2, 2,   // 1 2 3
  3, 0, 3,   // 4 5 6
  2, 2, 2 }; // 7 8 9

typedef map<unsigned,int> cachetype;
cachetype cache;

int nseq( int k, int n, int e=0 )
{
  e += k&1^1; // increment e if k is even.
  if( MAX_EVENS < e ) return 0;
  if( n <= 1 ) return 1;
  unsigned key = (n << 4 | k) << 3 | e; // n is left with 32-7=25 bits
  cachetype::const_iterator it = cache.find(key);
  if( it != cache.end() ) return it->second;
  int sum = 0;
  for( int i=0 ; i<jumpto_size[k] ; ++i ) sum += nseq( jumpto[k][i], n-1, e );
  return cache[key] = sum;
}

int main()
{
  for( int k=0 ; k<=9 ; ++k )
    for( int n=2 ; n<=8 ; ++n )
    {
      int count = nseq(k,n);
      cout << "k="<<k<<",n="<<n<<": "<<count<<endl;
      if( count == 0 ) break;
    }
  return 0;
}
Matt
  • 20,108
  • 1
  • 57
  • 70
  • 1
    `$m[k].inject(0) { |sum,j| sum + nseq( j, n-1, e ) }` - that (among other things) is rather far from using generic enough syntax to classify as proper pseudo-code in my book. Code written in some other language != pseudo-code. – Bernhard Barker Sep 21 '13 at 18:12
  • @Dukeling No disagreement there. That line in particular sums `nseq(j,n-1,e)` as j varies over `$m[k]`. E.g. for `k=1` this equals `nseq(6,n-1,e) + nseq(8,n-1,e)`. – Matt Sep 21 '13 at 18:42
  • @bjackfly It's hard for me to thoroughly examine your code since it is not complete. Specifically it doesn't contain the `GameData` class so I would have to be making too many guesses in order to definitely critique your code. Instead I re-wrote the ruby code into C++. Hope that helps. – Matt Sep 21 '13 at 19:35
  • 1
    @bjackfly Due to the added constraint of the maximum number of even digits, the maximum sequence length is 64, as verified by the above output. So for any values of `k` and `n`, `nseq(k,n)` is called no more than 54 times max. (This is easily confirmed by incrementing a global variable each time nseq() is called.) So for `n>=7`, the time complexity is O(1). If the maximum number of evens is itself considered a parameter, then the time and space complexity will be dependent on both that and `n`. Perhaps someone else, including yourself, can calculate this precisely. – Matt Sep 21 '13 at 21:42
  • Typo - I meant to say "...the maximum sequence length is 7 (of which there are 64 that start on 1), as verified by the above output." – Matt Sep 21 '13 at 21:53