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
4
  • 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<int,int> 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. Commented Sep 21, 2013 at 0: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? Commented Sep 21, 2013 at 0:24
  • @BenVoigt Yeah you're right. See my answer instead. Commented Sep 21, 2013 at 0: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? Commented Sep 27, 2013 at 0:10

1 Answer 1

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;
}
Sign up to request clarification or add additional context in comments.

5 Comments

$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.
@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).
@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.
@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.
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."

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.