Подтвердить что ты не робот

Сгенерируйте 10-значный номер с помощью клавиатуры телефона

С учетом клавиатуры телефона, как показано ниже:

1 2 3
4 5 6
7 8 9
  0

Сколько различных десятизначных чисел может быть сформировано начиная с 1? Ограничение состоит в том, что движение от 1 цифры до следующего похоже на движение Рыцаря в шахматной игре.

Например, если мы находимся в 1, то следующая цифра может быть либо 6, либо 8 если мы находимся в точке 6, то следующая цифра может быть 1, 7 или 0.

Допускается повторение цифр - 1616161616 - допустимое число.

Существует ли полиномиальный алгоритм времени, который решает эту проблему? Задача требует, чтобы мы просто указали количество десятизначных чисел и не обязательно перечисляли числа.

EDIT: Я пробовал моделировать это как график с каждой цифрой, имеющей 2 или 3 цифры в качестве своих соседей. Затем я использовал DFS для навигации до глубины 10 узлов, а затем увеличивал количество чисел каждый раз, когда я достигал глубины 10. Это, очевидно, не полиномиальное время. Предполагая, что у каждой цифры было всего 2 соседа, для этого потребовалось бы не менее 2 ^ 10 итераций.

Здесь переменная - это количество цифр. Я взял, например. 10 цифр. Он также может быть n-цифрами.

4b9b3361

Ответ 1

Конечно, это можно сделать в полиномиальное время. Это отличное упражнение в динамическом программировании или memoization.

Предположим, что N (число цифр) равно 10 для примера.

Подумайте об этом рекурсивно: сколько чисел я могу построить, используя 10 цифр, начиная с 1?

Ответ

[number of 9-digit numbers starting from 8] +
[number of 9-digit numbers starting from 6].

Итак, сколько "9-значных чисел, начиная с 8"? Ну,

[number of 8-digit numbers starting from 1] +
[number of 8-digit numbers starting from 3]

и т.д. Базовый случай достигается, когда вы задаете вопрос "Сколько 1-значных чисел начинается с X" (и ответ, очевидно, 1).

Когда дело доходит до сложности, ключевым наблюдением является то, что вы повторно используете ранее вычисленные решения. Это, например, ответ на "сколько пятизначных чисел, начиная с 3" есть, может использоваться как при ответе на "сколько 6-значных чисел, начиная с 8" AND ", сколько 6 -значные числа начинаются с 4". Это повторное использование заставляет сложность сжиматься от экспоненциального до многочлена.

Рассмотрим более детально сложность решения динамического программирования:

Такая реализация заполнила бы матрицу следующим образом:

num[1][i] = 1, for all 0<=i<=9   -- there are one 1-digit number starting from X.

for digits = 2...N
    for from = 0...9
        num[digits][from] = num[digits-1][successor 1 of from] +
                            num[digits-1][successor 2 of from] +
                            ...
                            num[digits-1][successor K of from]

return num[N][1]                 -- number of N-digit numbers starting from 1.

Алгоритм просто заполняет матрицу по одной ячейке за раз, а матрица имеет размерность 10 * N и, следовательно, работает в линейном времени.


Написал это с моей головы, пожалуйста, исправьте меня, если есть опечатки.

Ответ 2

Это можно сделать в O (log N). Рассмотрим клавиатуру и возможные движения на ней как график G (V, E), где вершины - это доступные цифры, а ребра - цифры, которые могут следовать за ними. Теперь для каждой выходной позиции я мы можем сформировать вектор Paths (i), содержащий число разных путей, к которым может быть достигнута каждая вершина. Теперь довольно легко увидеть, что для данной позиции я и цифры v возможные пути, которые она может (1) [v] = sum (Paths (i-1) [v2] * (1, если (v, v2) в E else 0) для v2 в V). Теперь это берет сумму каждой позиции, которая предшествует вектору, в соответствующую позицию в столбце матрицы смежности. Поэтому мы можем упростить это как Paths (i) = Paths (i-1) · A, где A - матрица смежности графа. Избавляясь от рекурсии и используя ассоциативность матричного умножения, это становится Paths (i) = Paths (1) · A ^ (i-1). Мы знаем Paths (1): у нас есть только один путь до цифры 1.

Общее количество путей для n-разрядного числа - это сумма путей для каждой цифры, поэтому окончательный алгоритм становится: TotalPaths (n) = sum ([1,0,0,0,0,0,0, 0,0,0] · A ^ (n-1))

Экспоненциальность может быть вычислена путем возведения в квадрат в O (log (n)) времени с учетом постоянного умножения времени, в противном случае O (M (n) * log (n)), где M (n) - сложность вашего любимого произвольного прецизионный алгоритм умножения для n чисел цифр.

Ответ 3

Простой ответ.

#include<stdio.h>

int a[10] = {2,2,2,2,3,0,3,2,2,2};
int b[10][3] = {{4,6},{6,8},{7,9},{4,8},{0,3,9},{},{1,7,0},{2,6},{1,3},{2,4}};

int count(int curr,int n)
{
    int sum = 0;
    if(n==10)
        return 1;
    else
    {
        int i = 0;
        int val = 0;
        for(i = 0; i < a[curr]; i++)
        {
            val = count(b[curr][i],n+1);
            sum += val;
        }
        return sum;
    }
}

int main()
{
    int n = 1;
    int val = count(1,0);
    printf("%d\n",val);
}

отмечать!!

Ответ 4

Время работы по времени:

#include <iostream>

constexpr int notValid(int x, int y) {
return !(( 1 == x && 3 == y ) || //zero on bottom.
         ( 0 <= x && 3 > x && //1-9
           0 <= y && 3 > y ));
}

class Knight {
    template<unsigned N > constexpr int move(int x, int y) {
        return notValid(x,y)? 0 : jump<N-1>(x,y);
    }

    template<unsigned N> constexpr int jump( int x, int y ) {
        return  move<N>(x+1, y-2) +
            move<N>(x-1, y-2) +
            move<N>(x+1, y+2) +
            move<N>(x-1, y+2) +
            move<N>(x+2, y+1) +
            move<N>(x-2, y+1) +
            move<N>(x+2, y-1) +
            move<N>(x-2, y-1);
    }

public:
    template<unsigned N> constexpr int count() {
        return move<N-1>(0,1) + move<N-1>(0,2) +
            move<N-1>(1,0) + move<N-1>(1,1) + move<N-1>(1,2) +
            move<N-1>(2,0) + move<N-1>(2,1) + move<N-1>(2,2);
    }
};

template<> constexpr int Knight::move<0>(int x, int y) { return notValid(x,y)? 0 : 1; }
template<> constexpr int Knight::count<0>() { return 0; } //terminal cases.
template<> constexpr int Knight::count<1>() { return 8; }


int main(int argc, char* argv[]) {
    static_assert( ( 16 == Knight().count<2>() ), "Fail on test with 2 lenght" );  // prof of performance
    static_assert( ( 35 == Knight().count<3>() ), "Fail on test with 3 lenght" );

    std::cout<< "Number of valid Knight phones numbers:" << Knight().count<10>() << std::endl;
    return 0;
}

Ответ 5

Я решил решить эту проблему и сделать ее максимально возможной. Это решение позволяет:

Определите свою собственную панель (телефонная панель, шахматная доска и т.д.)

Определите свою собственную шахматную фигуру (рыцарь, ладья, епископ и т.д.); вам придется написать конкретный класс и сгенерировать его из factory.

Извлеките несколько частей информации с помощью полезных методов.

Классы следующие:

PadNumber: класс, определяющий кнопку на клавиатуре телефона. Может быть переименован в "Квадрат", чтобы представить квадрат платы.

ChessPiece: абстрактный класс, который определяет поля для всех шахматных фигур.

Движение: интерфейс, который определяет методы перемещения и позволяет создавать factory фрагменты.

PieceFactory: класс factory для создания шахматных фигур.

Рыцарь: конкретный класс, который наследуется от ChessPiece и реализует Movement

PhoneChess: класс входа.

Драйвер: код драйвера.

ОК, вот код:)

package PhoneChess;

import java.awt.Point;

public class PadNumber {

private String number = "";
private Point coordinates = null;

public PadNumber(String number, Point coordinates)
{
    if(number != null && number.isEmpty()==false)
        this.number = number;
    else
        throw new IllegalArgumentException("Input cannot be null or empty.");

    if(coordinates == null || coordinates.x < 0 || coordinates.y < 0)
        throw new IllegalArgumentException();
    else
        this.coordinates = coordinates;

}

public String getNumber()
{
    return this.number;
}
public Integer getNumberAsNumber()
{
    return Integer.parseInt(this.number);
}

public Point getCoordinates()
{
    return this.coordinates;
}
public int getX()
{
    return this.coordinates.x;
}
public int getY()
{
    return this.coordinates.y;
}

}

фишка

package PhoneChess;

import java.util.HashMap;
import java.util.List;

public abstract class ChessPiece implements Movement {

protected String name = "";
protected HashMap<PadNumber, List<PadNumber>> moves = null;
protected Integer fullNumbers = 0;
protected int[] movesFrom = null;
protected PadNumber[][] thePad = null;
}

Интерфейс перемещения:

package PhoneChess;

import java.util.List;

public interface Movement 
{
public Integer findNumbers(PadNumber start, Integer digits);
public abstract boolean canMove(PadNumber from, PadNumber to);
public List<PadNumber> allowedMoves(PadNumber from);
public Integer countAllowedMoves(PadNumber from);
}

PieceFactory

package PhoneChess;

public class PieceFactory 
{
    public ChessPiece getPiece(String piece, PadNumber[][] thePad)
    {
    if(thePad == null || thePad.length == 0 || thePad[0].length == 0)
        throw new IllegalArgumentException("Invalid pad");
    if(piece == null)
        throw new IllegalArgumentException("Invalid chess piece");

    if(piece.equalsIgnoreCase("Knight"))
        return new Knight("Knight", thePad);
    else
        return null;
}
}

Класс рыцаря

package PhoneChess;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public final class Knight extends ChessPiece implements Movement {

/**Knight movements
 * One horizontal, followed by two vertical
 * Or 
 * One vertical, followed by two horizontal
 * @param name
 */

public Knight(String name, PadNumber[][] thePad)
{
    if(name == null || name.isEmpty() == true)
        throw new IllegalArgumentException("Name cannot be null or empty");

    this.name = name;
    this.thePad = thePad;
    this.moves = new HashMap<>();
}


private Integer fullNumbers = null;

@Override
public Integer findNumbers(PadNumber start, Integer digits) 
{
    if(start == null || "*".equals(start.getNumber()) || "#".equals(start.getNumber()) ) { throw new IllegalArgumentException("Invalid start point"); }
    if(start.getNumberAsNumber() == 5) { return 0; } //Consider adding an 'allowSpecialChars' condition
    if(digits == 1) { return 1; };

    //Init
    this.movesFrom = new int[thePad.length * thePad[0].length];
    for(int i = 0; i < this.movesFrom.length; i++)
        this.movesFrom[i] = -1;

    fullNumbers = 0;
    findNumbers(start, digits, 1);      
    return fullNumbers;
}

private void findNumbers(PadNumber start, Integer digits, Integer currentDigits)
{
    //Base condition
    if(currentDigits == digits)
    {
        //Reset
        currentDigits = 1; 
        fullNumbers++; 
        return; 
    }
    if(!this.moves.containsKey(start))
        allowedMoves(start);

    List<PadNumber> options = this.moves.get(start);
    if(options != null)
    {
        currentDigits++; //More digits to be got
        for(PadNumber option : options)
            findNumbers(option, digits, currentDigits);
    }
}

@Override
public boolean canMove(PadNumber from, PadNumber to) 
{
    //Is the moves list available?
    if(!this.moves.containsKey(from.getNumber()))
    {
        //No? Process.
        allowedMoves(from);
    }
    if(this.moves.get(from) != null)
    {
        for(PadNumber option : this.moves.get(from))
        {
            if(option.getNumber().equals(to.getNumber()))
                return true;
        }
    }
    return false;

}

/***
 * Overriden method that defines each Piece movement restrictions.
 */
@Override
public List<PadNumber> allowedMoves(PadNumber from) 
{
    //First encounter
    if(this.moves == null)
        this.moves = new HashMap<>();


    if(this.moves.containsKey(from))
        return this.moves.get(from);
    else
    {
        List<PadNumber> found = new ArrayList<>();
        int row = from.getY();//rows
        int col = from.getX();//columns

        //Cases:
        //1. One horizontal move each way followed by two vertical moves each way
        if(col-1 >= 0 && row-2 >= 0)//valid
        {
            if(thePad[row-2][col-1].getNumber().equals("*") == false && 
                    thePad[row-2][col-1].getNumber().equals("#") == false)
            {
                found.add(thePad[row-2][col-1]);
                this.movesFrom[from.getNumberAsNumber()] = this.movesFrom[from.getNumberAsNumber()] + 1;
            }

        }
        if(col-1 >= 0 && row+2 < thePad.length)//valid
        {
            if(thePad[row+2][col-1].getNumber().equals("*") == false && 
                    thePad[row+2][col-1].getNumber().equals("#") == false)
            {
                found.add(thePad[row+2][col-1]);
                this.movesFrom[from.getNumberAsNumber()] = this.movesFrom[from.getNumberAsNumber()] + 1;
            }
        }
        if(col+1 < thePad[0].length && row+2 < thePad.length)//valid
        {
            if(thePad[row+2][col+1].getNumber().equals("*") == false && 
                    thePad[row+2][col+1].getNumber().equals("#") == false)
            {
                found.add(thePad[row+2][col+1]);
                this.movesFrom[from.getNumberAsNumber()] = this.movesFrom[from.getNumberAsNumber()] + 1;
            }
        }
        if(col+1 < thePad[0].length && row-2 >= 0)//valid
        {
            if(thePad[row-2][col+1].getNumber().equals("*") == false && 
                    thePad[row-2][col+1].getNumber().equals("#") == false)
            found.add(thePad[row-2][col+1]);
        }
        //Case 2. One vertical move each way follow by two horizontal moves each way

        if(col-2 >= 0 && row-1 >= 0)
        {
            if(thePad[row-1][col-2].getNumber().equals("*") == false && 
                    thePad[row-1][col-2].getNumber().equals("#") == false)
            found.add(thePad[row-1][col-2]);
        }
        if(col-2 >= 0 && row+1 < thePad.length)
        {
            if(thePad[row+1][col-2].getNumber().equals("*") == false && 
                    thePad[row+1][col-2].getNumber().equals("#") == false)
            found.add(thePad[row+1][col-2]);
        }

        if(col+2 < thePad[0].length && row-1 >= 0)
        {
            if(thePad[row-1][col+2].getNumber().equals("*") == false && 
                    thePad[row-1][col+2].getNumber().equals("#") == false)
            found.add(thePad[row-1][col+2]);
        }
        if(col+2 < thePad[0].length && row+1 < thePad.length)
        {
            if(thePad[row+1][col+2].getNumber().equals("*") == false && 
                    thePad[row+1][col+2].getNumber().equals("#") == false)
            found.add(thePad[row+1][col+2]);
        }

        if(found.size() > 0)
        {
            this.moves.put(from, found);
            this.movesFrom[from.getNumberAsNumber()] = found.size();
        }
        else
        {
            this.moves.put(from, null); //for example the Knight cannot move from 5 to anywhere
            this.movesFrom[from.getNumberAsNumber()] = 0;
        }
    }

    return this.moves.get(from);


}

@Override
public Integer countAllowedMoves(PadNumber from) 
{
    int start = from.getNumberAsNumber();

    if(movesFrom[start] != -1)
        return movesFrom[start];
    else
    {
        movesFrom[start] = allowedMoves(from).size();
    }
    return movesFrom[start];
}

@Override
public String toString()
{
    return this.name;
}

}

Класс участника PhoneChess

package PhoneChess;


public final class PhoneChess 
{
private ChessPiece thePiece = null;
private PieceFactory factory = null;

public ChessPiece ThePiece()
{
    return this.thePiece;
}

public PhoneChess(PadNumber[][] thePad, String piece)
{
    if(thePad == null || thePad.length == 0 || thePad[0].length == 0)
        throw new IllegalArgumentException("Invalid pad");
    if(piece == null)
        throw new IllegalArgumentException("Invalid chess piece");

    this.factory = new PieceFactory();
    this.thePiece = this.factory.getPiece(piece, thePad);
}

public Integer findPossibleDigits(PadNumber start, Integer digits)
{
    if(digits <= 0)
        throw new IllegalArgumentException("Digits cannot be less than or equal to zero");

    return thePiece.findNumbers(start, digits);
}

public boolean isValidMove(PadNumber from, PadNumber to)
{
    return this.thePiece.canMove(from, to);
}

}

Код драйвера:

public static void main(String[] args) {


    PadNumber[][] thePad = new PadNumber[4][3];
    thePad[0][0] = new PadNumber("1", new Point(0,0));
    thePad[0][1] = new PadNumber("2", new Point(1,0));
    thePad[0][2] = new PadNumber("3",new Point(2,0));
    thePad[1][0] = new PadNumber("4",new Point(0,1));
    thePad[1][1] = new PadNumber("5",new Point(1,1));
    thePad[1][2] = new PadNumber("6", new Point(2,1));
    thePad[2][0] = new PadNumber("7", new Point(0,2));
    thePad[2][1] = new PadNumber("8", new Point(1,2));
    thePad[2][2] = new PadNumber("9", new Point(2,2));
    thePad[3][0] = new PadNumber("*", new Point(0,3));
    thePad[3][1] = new PadNumber("0", new Point(1,3));
    thePad[3][2] = new PadNumber("#", new Point(2,3));

    PhoneChess phoneChess = new PhoneChess(thePad, "Knight");
    System.out.println(phoneChess.findPossibleDigits(thePad[0][1],4));
}

}

Ответ 6

Метод возвращает список из десятизначных чисел, начиная с 1. Опять же, число равно 1424.

  public ArrayList<String> getList(int digit, int length, String base ){
    ArrayList<String> list = new ArrayList<String>();
    if(length == 1){
        list.add(base);
        return list;
    }
    ArrayList<String> temp;

    for(int i : b[digit]){
        String newBase = base +i;
        list.addAll(getList(i, length -1, newBase ));
    }
    return list;
}

Ответ 7

Я не уверен, что что-то пропустил, но, прочитав описание проблемы, я пришел к этому решению. Он имеет сложность времени O (n) и сложность пространства O (1).

Я понял, что номер 1 находится в углу, верно? В каждом углу вы можете либо переместиться на одну из сторон (4 из 9 и 3, или 6 из 7 на 1), либо одну из "вертикальных" сторон (8 из 3 и 1 или 2 из 9 и 7). Итак, углы добавляют два хода: боковое движение и "вертикальное" движение. Это верно для всех четырех углов (1,3,9,7).

С каждой стороны вы можете либо перейти на два угла (7 и 1 из 6, 9 и 3 из 4), либо вы можете добраться до нижней клавиши (0). Это три хода. Два угла и одно нижнее.

В нижней клавише (0) вы можете перейти на обе стороны (4 и 6). Итак, на каждом шаге вы проверяете все возможные окончания для пути предыдущей длины (то есть, сколько закончилось на углу, стороне, "вертикальной" или "нижней" нулевой клавише), а затем генерировать новый конец рассчитывается в соответствии с правилами генерации, указанными ранее.

  • Каждый конец угла добавляет сторону и вертикаль.
  • Каждая сторона заканчивается добавлением 2 углов и нижней части.
  • Каждый вертикальный конец добавляет 2 угла.
  • Каждый нижний конец добавляет две стороны.

создание возможностей с предыдущих шагов

Если вы начинаете с ключа "1", вы начинаете с одного из возможных угловых решений, на каждом шаге вы подсчитываете количество угловых, боковых, вертикальных и нижних концов предыдущего шага, а затем применяете правила для создания следующего кол.

В простом javascript-коде.

function paths(n) {
    //Index to 0
    var corners = 1;
    var verticals = 0;
    var bottom = 0;
    var sides = 0;

    if (n <= 0) {
        //No moves possible for paths without length 
        return 0;
    }

    for (var i = 1; i < n; i++) {
        var previousCorners = corners;
        var previousVerticals = verticals;
        var previousBottom = bottom;
        var previousSides = sides;

        sides = 1 * previousCorners + 2 * previousBottom;
        verticals = 1 * previousCorners;
        bottom = 1 * previousSides;
        corners = 2 * previousSides + 2 * previousVerticals;
        //console.log("Moves: %d, Length: %d, Sides: %d, Verticals: %d, Bottom: %d, Corners: %d, Total: %d", i, i + 1, sides, verticals, bottom, corners, sides+verticals+bottom+corners);  
    }

    return sides + verticals + bottom + corners;

}

for (var i = 0; i <= 10; i++) {
    console.log(paths(i));  
}

Ответ 8

Эта проблема может быть также смоделирована как проблема Проблема ограничения ограничений (например, CSP для краткости).

Я предлагаю использовать решающий Minion (быстрый и масштабируемый), который вы можете найти здесь.

Моделирование может быть утомительным и продолжительным (крутая кривая обучения).

Вместо использования ввода языка Minion мой совет состоит в том, чтобы сформулировать модель с независимым языком моделирования решателя, таким как ESSENCE и найти конвертер соответственно.

Ответ 9

//Both the iterative and recursive with memorize shows count as 1424 for 10 digit numbers starting with 1. 
int[][] b = {{4,6},{6,8},{7,9},{4,8},{0,3,9},{},{1,7,0},{2,6},{1,3},{2,4}};
public int countIterative(int digit, int length) {
    int[][] matrix = new int[length][10];
    for(int dig =0; dig <=9; dig++){
          matrix[0][dig] = 1;
    }
    for(int len = 1; len < length; len++){
        for(int dig =0; dig <=9; dig++){
          int sum = 0;
          for(int i : b[dig]){
            sum += matrix[len-1][i];
          }
          matrix[len][dig] = sum;
        }
    }
    return matrix[length-1][digit];
}

public int count(int index, int length, int[][] matrix ){
    int sum = 0;
    if(matrix[length-1][index] > 0){
        System.out.println("getting value from memoize:"+index + "length:"+ length);
        return matrix[length-1][index];
    }
    if( length == 1){
        return 1;
    }
    for(int i: b[index] )  {
         sum += count(i, length-1,matrix);
    }
    matrix[length-1][index] = sum;
    return sum;
}

Ответ 10

Рекурсивный подход к memoization:

vector<vector<int>> lupt = { {4, 6}, {6, 8}, {9, 7}, {4, 8}, {3, 9, 0},
                             {},     {1,7,0}, {6, 2}, {1, 3}, {2, 4} };

int numPhoneNumbersUtil(int startdigit, int& phonenumberlength, int currCount, map< pair<int,int>,int>& memT)
{
    int noOfCombs = 0;
    vector<int> enddigits;

    auto it = memT.find(make_pair(startdigit,currCount));
    if(it != memT.end())
    {
        noOfCombs = it->second;
        return noOfCombs;
    }

    if(currCount == phonenumberlength)
    {
        return 1;
    }

    enddigits = lupt[startdigit];
    for(auto it : enddigits)
    {
        noOfCombs += numPhoneNumbersUtil(it, phonenumberlength, currCount + 1, memT);
    }

    memT.insert(make_pair(make_pair(startdigit,currCount), noOfCombs));
    return memT[make_pair(startdigit,currCount)];

}

int numPhoneNumbers(int startdigit, int phonenumberlength)
{
    map<pair<int,int>,int> memT;
    int currentCount = 1; //the first digit has already been added
    return  numPhoneNumbersUtil(startdigit, phonenumberlength, currentCount, memT);
}

Ответ 11

Я реализовал модели грубой силы и динамического программирования

import queue


def chess_numbers_bf(start, length):
    if length <= 0:
        return 0
    phone = [[7, 5], [6, 8], [3, 7], [9, 2, 8], [], [6, 9, 0], [1, 5], [0, 2], [3, 1], [5, 3]]
    total = 0
    q = queue.Queue()
    q.put((start, 1))

    while not q.empty():
        front = q.get()
        val = front[0]
        len_ = front[1]
        if len_ < length:
            for elm in phone[val]:
                q.put((elm, len_ + 1))
        else:
            total += 1
    return total


def chess_numbers_dp(start, length):
    if length <= 0:
        return 0

    phone = [[7, 5], [6, 8], [3, 7], [9, 2, 8], [], [6, 9, 0], [1, 5], [0, 2], [3, 1], [5, 3]]
    memory = {}

    def __chess_numbers_dp(s, l):
        if (s, l) in memory:
            return memory[(s, l)]
        elif l == length - 1:
            memory[(s, l)] = 1
            return 1
        else:
            total_n_ways = 0
            for number in phone[s]:
                total_n_ways += __chess_numbers_dp(number, l+1)
            memory[(s, l)] = total_n_ways
            return total_n_ways
    return __chess_numbers_dp(start, 0)


# bf
for i in range(0, 10):
    print(i, chess_numbers_bf(3, i))
print('\n')

for i in range(0, 10):
    print(i, chess_numbers_bf(9, i))
print('\n')

# dp
for i in range(0, 10):
    print(i, chess_numbers_dp(3, i))
print('\n')

# dp
for i in range(0, 10):
    print(i, chess_numbers_dp(9, i))
print('\n')

Ответ 12

Рекурсивная функция в Java:

public static int countPhoneNumbers (int n, int r, int c) {
        if (outOfBounds(r,c)) {
            return 0;
        } else {
            char button = buttons[r][c];
            if (button  == '.') {
                // visited
                return 0;
            }  else {
                buttons[r][c] = '.'; // record this position so don't revisit.
                // Count all possible phone numbers with one less digit starting
                int result=0;
                result = countPhoneNumbers(n-1,r-2,c-1)
                                         + countPhoneNumbers(n-1,r-2,c+1)
                                         + countPhoneNumbers(n-1,r+2,c-1)
                                         + countPhoneNumbers(n-1,r+2,c+1)
                                         + countPhoneNumbers(n-1,r-1,c-2)
                                         + countPhoneNumbers(n-1,r-1,c+2)
                                         + countPhoneNumbers(n-1,r+1,c-2)
                                         + countPhoneNumbers(n-1,r+1,c+2);
                }
                buttons[r][c] = button; // Remove record from position.
                return result; 
            }
        }
    }