Решение головоломки N-ферзей с помощью TypeScript
Задача N-ферзей — это классическая задача о размещении N ферзей на шахматной доске NxN таким образом, чтобы никакие два ферзя не атаковали друг друга. В этой статье мы рассмотрим решение этой головоломки с помощью TypeScript.
Проблема
Головоломка N-Queens — известная головоломка, которую изучали на протяжении веков. Впервые он был введен в 1848 году шахматистом Максом Беззелем и с тех пор пользуется популярностью. Задача проста: расставить N ферзей на шахматной доске NxN так, чтобы никакие два ферзя не атаковали друг друга. Проблема сложная, потому что ферзи могут двигаться по горизонтали, вертикали и диагонали, а это значит, что они могут атаковать любого другого ферзя в поле зрения.
Решение
Решение, которое мы рассмотрим, — это алгоритм поиска с возвратом. Поиск с возвратом — это общий алгоритмический метод, который включает поиск в наборе возможных решений до тех пор, пока не будет найдено правильное. В случае головоломки с N-ферзями мы будем использовать возврат для поиска всех возможных мест размещения ферзей, пока не найдем правильное решение.
Вот код TypeScript для нашего решения:
function solveNQueens(n: number): string[][] { // create a 2D array to represent the board const board: string[][] = Array.from(Array(n), () => new Array(n).fill(".")); // create a result array to store the final result const result: string[][] = []; // function backtrack to find all possible solutions function backtrack(board: string[][], row: number): void { // if we have reached the end of the board, we have found a solution if (row === n) { // add the solution to the result array result.push(board.map((row) => row.join(""))); return; } // iterate through all the columns for (let col = 0; col < n; col++) { // if the position is valid (no queens in the same column or diagonal) if (isValid(board, row, col)) { // place a queen at the current position board[row][col] = "Q"; // recursively move to the next row backtrack(board, row + 1); // remove the queen from the current position after we have finished exploring board[row][col] = "."; } } } // helper function isValid to check if the current position is valid function isValid(board: string[][], row: number, col: number): boolean { // iterate through all the rows above the current row for (let i = 0; i < row; i++) { // if there is a queen in the same column, return false if (board[i][col] === "Q") { return false; } } // iterate through the left diagonal for (let i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) { // if there is a queen in the same diagonal, return false if (board[i][j] === "Q") { return false; } } // iterate through the right diagonal for (let i = row - 1, j = col + 1; i >= 0 && j < n; i--, j++) { // if there is a queen in the same diagonal, return false if (board[i][j] === "Q") { return false; } } // if we have not found any queens in the same column or diagonal, return true return true; } // call the backtrack function to start exploring all the possible solutions backtrack(board, 0); // return the result array return result; }
Разберем код построчно.
Объявление функции
function solveNQueens(n: number): string[][] {
Функция solveNQueens
принимает целое число n
в качестве входных данных и возвращает массив массивов строк, представляющих все различные решения головоломки N-ферзей.
Определение результата
const result: string[][] = [];
Мы определяем пустой массив result
для хранения наших решений.
Функция возврата
function backtrack(board: string[][], row: number): void {
В функции backtrack
реализован алгоритм поиска с возвратом. Он принимает двумерный массив board
, представляющий шахматную доску, и целое число row
, представляющее текущую оцениваемую строку.
if (row === n) { result.push(board.map((row) => row.join(''))); return; }
Если row
равно n
, мы нашли правильное решение, поэтому мы помещаем копию доски в result
и возвращаемся.
for (let col = 0; col < n; col++) { if (isValid(board, row, col)) { board[row][col] = 'Q'; backtrack(board, row + 1); board[row][col] = '.'; } }
Если мы еще не нашли действительного решения, мы перебираем каждый столбец в текущей строке и проверяем, допустимо ли размещение ферзя в этой позиции, используя функцию isValid
. Если размещение допустимо, мы помечаем эту позицию ферзем (board[row][col] = 'Q'
) и рекурсивно вызываем backtrack
в следующем ряду (backtrack(board, row + 1)
). После возврата рекурсивного вызова мы убираем ферзя с позиции (board[row][col] = '.'
) и переходим к следующему столбцу.
Функция isValid
function isValid(board: string[][], row: number, col: number): boolean {
Функция isValid
проверяет, является ли данная позиция допустимым размещением ферзя на шахматной доске.
for (let i = 0; i < row; i++) { if (board[i][col] === 'Q') { return false; } }
Сначала мы проверяем, есть ли ферзь в том же столбце, что и данная позиция. Если есть, размещение недействительно.
for (let i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) { if (board[i][j] === 'Q') { return false; } }
Затем мы проверяем, есть ли ферзь на той же диагонали, идущей из верхнего левого угла в нижний правый, что и данная позиция. Если есть, размещение недействительно.
for (let i = row - 1, j = col + 1; i >= 0 && j < n; i--, j++) { if (board[i][j] === 'Q') { return false; } }
Наконец, мы проверяем, есть ли ферзь на той же диагонали, идущей из верхнего правого угла в нижний левый, что и данная позиция. Если есть, размещение недействительно. Если ни одно из этих условий не выполняется, размещение считается действительным.
Инициализация платы
const board: string[][] = Array.from(Array(n), () => new Array(n).fill('.'));
Мы определяем массив board
как двумерный массив n
на n
, заполненный '.'
.
Вызов функции возврата
backtrack(board, 0);
Мы вызываем функцию backtrack
с board
и начальным row
из 0
.
Возврат результата
return result;
Мы возвращаем result
, содержащее все различные решения головоломки N-Queens.
Пример использования
Вот несколько примеров использования функции solveNQueens
:
console.log(solveNQueens(4)); // Output: [[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]] console.log(solveNQueens(1)); // Output: [["Q"]]
Заключение
В этой статье мы рассмотрели решение головоломки N-Queens на TypeScript с использованием поиска с возвратом. Хотя решение относительно короткое, оно довольно сложное и включает много рекурсий. Однако, приложив немного практики и терпения, вы справитесь с этой и другими задачами поиска с возвратом.