Алгоритм восьми ферзей

Ранее я задавал вопрос о решении проблемы восьми ферзей с помощью Java. У меня есть алгоритм обратного отслеживания для решения проблемы.

Я пытался использовать этот алгоритм, но не знаю, что не так с моим кодом. Он размещает только до 7 ферзей.

Вот класс королевы:

    public class Queen {
    //Number of rows or columns
    public static final int BOARD_SIZE = 8;

    boolean[][] board;
    //Indicate an empty square
    public static final boolean EMPTY = false;
    //Indicate a square which containing a queen
    public static final boolean QUEEN = true;
    //Number of moves
    public static final int MOVES = 4;
    //Horizontal moves
    int[] horizontal;
    //Vertical moves
    int[] vertical;

    public int queens = 0;

    public Queen() {
        //Constructor creates an empty board
        board = new boolean[BOARD_SIZE][BOARD_SIZE];
        for (int row = 0; row < board.length; row++) {
            for (int col = 0; col < board[row].length; col++) {
                board[row][col] = EMPTY;
            }
        }

        horizontal = new int[MOVES];
        vertical = new int[MOVES];
        // up right
        horizontal[0] = -1;
        vertical[0] = 1; 
        // down left
        horizontal[1] = 1;
        vertical[1] = -1;
        // up left
        horizontal[2] = -1;
        vertical[2] = -1;
        // down right
        horizontal[3] = 1;
        vertical[3] = 1;
    }

    public boolean placeQueens (int column) {
        if (column > BOARD_SIZE) {
            return true;
        }
        else {
            boolean queenPlaced = false;
            int row = 1;

            while (!queenPlaced && row < BOARD_SIZE) {
                if (isUnderAttack(row, column)) {
                    ++row;
                }// end if
                else{
                    setQueen(row, column);
                    queenPlaced = placeQueens(column + 1);
                    if (!queenPlaced) {
                        removeQueen(row,column);
                        ++row;
                    }// end if
                }// end else
            }// end while
            return queenPlaced;
        }// end else
    }

    private void removeQueen(int row, int column) {
        board[row][column] = EMPTY;
        System.out.printf("queen REMOVED from [%d][%d]\n", row, column);
    --queens;
    }

    private void setQueen(int row, int column) {
        board[row][column] = QUEEN;
        System.out.printf("queen PLACED in [%d][%d]\n", row, column);
        ++queens;
    }

    public boolean isUnderAttack(int row, int col) {
        boolean condition = false;
        // check row
        for (int column = 0; column < BOARD_SIZE; column++) {
            if ((board[row][column] == true)) {
                condition = true;
            }
        }

        // check column
        for (int row_ = 0; row_ < board.length; row_++) {
            if (board[row_][col] == true) {
                        condition = true;
            }
        }

        // check diagonal
        for (int row_ = row, col_ = col; row_ >= 0 && col_ < 8; row_ += horizontal[0], col_ += vertical[0]) {
            if (board[row_][col_] == true) {
                condition = true;
            }
        }
        for (int row_ = row, col_ = col; row_ < 8 && col_ >= 0; row_ += horizontal[1], col_ += vertical[1]) {
            if (board[row_][col_] == true) {
                condition = true;
            }
        }
        for (int row_ = row, col_ = col; row_ >= 0 && col_ >= 0; row_ += horizontal[2], col_ += vertical[2]) {
            if (board[row_][col_] == true) {
                condition = true;
            }
        }
        for (int row_ = row, col_ = col; row_ < 8 && col_ < 8; row_ += horizontal[3], col_ += vertical[3]) {
            if (board[row_][col_] == true) {
                condition = true;
            }
        }

        return condition;
    }

    public void displayBoard () {
        int counter = 0;
        for (int row = 0; row < board.length; row++) {
            for (int col = 0; col < board[row].length; col++) {
                if (board[row][col] == true) {
                    System.out.printf("|%s|", "x");
                    counter++;
                }
                else {              
                    System.out.printf("|%s|", "o");
                }
            }
            System.out.println();
        }

        System.out.printf("%d queens has been placed\n", counter);
    }
}

person kzidane    schedule 15.11.2012    source источник
comment
Я только что создал свое эффективное решение для обратного отслеживания на Python здесь, за десятки секунд оно находит все решения для 1- 8 ферзей и через несколько минут 9 ферзей..   -  person Arty    schedule 29.09.2020


Ответы (3)


В Java массивы 0-индексированы, что означает, что первый элемент имеет индекс 0. Вы похоже, вы не совсем поняли этот важный факт, в результате чего вы пишете код со многими неправильными ошибки на единицу.

Одна проблема здесь:

int row = 1;

Так должно быть:

int row = 0;

Вторая проблема здесь:

if (column > BOARD_SIZE) {
    return true;
}

Это должно быть так:

if (column >= BOARD_SIZE) {
    return true;
}

Вы не опубликовали остальную часть своего кода, но я готов поспорить, что в вашем коде есть третья ошибка, когда вы вызываете метод placeQueens. Если я знаю, что вы за человек, то вы, вероятно, сделали это:

queen.placeQueens(1);

Но должно быть так:

queen.placeQueens(0);

Со всеми этими изменениями он работает так, как ожидалось. Окончательный результат:

|x||o||o||o||o||o||o||o|
|o||o||o||o||o||o||x||o|
|o||o||o||o||x||o||o||o|
|o||o||o||o||o||o||o||x|
|o||x||o||o||o||o||o||o|
|o||o||o||x||o||o||o||o|
|o||o||o||o||o||x||o||o|
|o||o||x||o||o||o||o||o|
8 queens has been placed

Посмотрите, как это работает онлайн: ideone.

person Mark Byers    schedule 15.11.2012
comment
Ну, ты был почти там. Вы правильно поняли рекурсивный алгоритм, что является самой сложной частью этой проблемы. Вам просто нужно помнить об использовании 0-индексации. - person Mark Byers; 15.11.2012

В методе isUnderAttack есть несколько хардкодов:

// проверяем диагональ на место использования 8 с помощью BOARD_SIZE

использовать:

col_ < BOARD_SIZE   

вместо

col_ < 8

и было бы лучше сделать BOARD_SIZE не статическим, а сделать его входным параметром, чтобы сделать код более общим и выполнить тест для boardSize = 4 или 12

person Arman Melkumyan    schedule 16.07.2018

Я написал общий код, который работает для любого числа ферзей.

Результат представлен 0 или 1. 1 - дама, 0 - пустая клетка.

static int[][] setupEightQueens(int queensNum) {
    if (queensNum <= 0)
        return new int[][] { {} };
    int[][] chessField = new int[queensNum][queensNum];
    int n = chessField.length;
    int startJ = 0;
    for (int i = 0; i < n; i++) {
        for (int j = startJ; j < n; j += 2) {
            chessField[j][i] = 1;
            i++;
        }
        i--;
        startJ++;
    }
    return chessField;
}

вывод для проверенных 4, 8, 11 кол-во ферзей:

__________________________
ферзей: 4
1 0 0 0
0 0 1 0
0 1 0 0
0 0 0 1
__________________________
ферзей: 8
1 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0
0 1 0 0 0 0 0 0
0 0 0 0 0 1 0 0
0 0 1 0 0 0 0 0
0 0 0 0 0 0 0 1 0
0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 1
__________________________
ферзей: 11
1 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 0 0 0 0
0 1 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1 0 0 0
0 0 1 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 1 0 0
0 0 0 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 1 0
0 0 0 0 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 1
0 0 0 0 0 1 0 0 0 0 0


person Arman Melkumyan    schedule 15.07.2018
comment
if (queensNum &lt;= 0) Это не похоже на допустимый синтаксис. - person CertainPerformance; 15.07.2018
comment
Я исправил это. Результат теста с n=4 неверен. Поэтому нам нужно добавить функцию проверки возможного пересечения с другим ферзем. - person Arman Melkumyan; 16.07.2018
comment
Все еще выглядит неправильно - посмотрите свой код в своем ответе, он говорит if (queensNum &lt;= 0) - person CertainPerformance; 16.07.2018
comment
Проверьте еще раз, пожалуйста. - person Arman Melkumyan; 16.07.2018
comment
Ваш результат для 4 ферзей также явно неверен. - person Turksarama; 16.07.2018
comment
Я вижу, что результат 4 неверен. Мне нужно использовать функцию, чтобы вернуться и переставить ферзей в новую позицию. Но основная цель алгоритмов — сократить шаги по обходу элементов массива столбцов и строк, перейдя к элементу ntext.next вот так j += 2 и сразу же делая i++ для перехода к следующей строке, а при использовании startJ - это стартовое место для королевы. Таким образом, уменьшается количество шагов перемещения. но вам нужно проверить isUnderAttack. -если правда. затем сбросить и начать с lastStartColumnInInxed и row = 0; - person Arman Melkumyan; 16.07.2018