Skip to content

Latest commit

 

History

History

37_Sudoku_Solver

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 

Решение задачи 37. Sudoku Solver

Как и следует из названия задачи, нам предлагают решить головоломку Sudoku, вернее, один из ее популярных вариантов.

На вход поступает двумерный массив char размера 9 х 9, где пустые клетки обозначены символом `.`.

Правила такие:

  • В каждой строке числа от 1 - 9 встречаются строго по одному разу.
  • В каждом столбце числа от 1 - 9 встречаются строго по одному разу.
  • Это же правило касается каждого квадрата 3 х 3, которых на поле 9.

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

Для этого нужно на каждом шаге точно знать какие числа уже использованы для каждого ряда, строки и квадрата. Я использую массивы целых чисел - 9 чисел для рядов, 9 - для столбцов, 9 - для квадратов - в которых с помощью битовых операторов включаю нужные биты, обозначая, что число "занято", то есть выставить его на клетку в соответствующем столбце, ряду и квадрате мы не можем.

Перед тем как приступить к решению потребуется составить карту уже присутствующих на поле чисел. То есть выставить нужные биты в рядах, столбцах и квадратах. Для этого использую метод FillBoard(), который, в свою очередь, вызывает метод ToggleBit(y, x, k), переключающий бит из 0 в 1 и обратно оператором ^ или XOR. Для перевода координат в индексы служебных массивов, и для удобного доступа по индексам реализован метод GetPtrs(y, x).

Непосредственно решением занимается метод Solve(y, x), формирующий цепь рекурсивных вызовов, где каждый такой вызов - шаг вперед. Для проверки доступности очередного числа реализован метод CanPut(y, x, k). Если нет доступных чисел, вызов завершается, происходит обратный ход рекурсии до момента, когда появляется возможность продвинуться вперед с другим числом. Успешным завершением всей цепи вызовов будет базовый случай - вызов Solve(y, x) для y == 9, x == 0, что означает выход на позицию следующюю после обработки правой нижней позиции.

Мое решение лежит здесь.