Логические ошибки возврата/рекурсии N-Queens?

Я пытаюсь решить эту проблему в качестве практического упражнения для моего предстоящего теста. Для этого мне нужно написать программу на C++, которая запрашивает ввод «размера доски» (nxn) и «количества ферзей», а затем выполняет задачу «n-ферзей».

Эта задача с n ферзями отличается от «обычной» задачи с n ферзями тем, что количество ферзей и размер доски можно варьировать, а если доска не полностью заполнена, вместо нее заменяются пустые места.

Пример вывода для ввода размера «8» и номера ферзя «4» можно увидеть ниже:

O.......
..O.....
....O...
.O......
...­-..­.-
........
...­-.-..
...­-.­.-.

где «O» представляет собой пространство, которое занято ферзем, «.» представляет пространство, которое заблокировано другим ферзем, а "-" представляет пространство, которое может быть занято другим ферзем, если пользователь введет большее количество ферзей (т. е. открытое пространство).

Дело в том, что я закодировал проблему, и это дает мне ЧРЕЗВЫЧАЙНО противоречивые результаты. (пример: ввод 4,4 работает, 5,5 работает, 6,6 не работает, 7,7 работает, 8,8 не работает, 2 ,1 не работает... список можно продолжать и продолжать). Я обнаружил, что виновником является комбинация цикла for и рекурсии, возвращающейся вниз по стеку после ее завершения, что вызывает несколько ошибок в зависимости от ситуации. Мой вопрос в том, как мне исправить цикл рекурсии, чтобы он по-прежнему мог вернуться, но при этом не вызывал ненужных ошибок? Я новичок в идее «возврата» в сочетании с рекурсией; что я могу сделать, чтобы улучшить мой метод возврата в будущем?

Мой код выглядит следующим образом:

#include <iostream>
#include <cstdlib>
using namespace std;

void readBoard(char board[100][100], int size);
void printBoard(char board[100][100], int size);
bool findOpenSpot(char board[100][100], int row, int col, int size);
bool nQueenSolver(char board[100][100], int row, int size, int queenNumber);

int main()
{
    int queenNumber;
    int size;
    char b[100][100];
    cout << "What size board do you want?" << endl;
    cin >> size;
    readBoard(b, size);
    printBoard(b, size);
    cout << "How many queens do you want to place?" << endl;
    cin >> queenNumber;
    if (queenNumber > size)
    {
        cout << "Impossible." << endl;
        exit(0);
    }
    if (nQueenSolver(b, 0, size, queenNumber) == true)
    {
        printBoard(b, size);
    }
    else
    {
        cout << "Impossible." << endl;
    }
    return 0;

}
bool nQueenSolver(char board[100][100], int row, int size, int queenNumber)
{
    if (row >= size)
    {
        return true;
    }

    for (int j=0; j<size; j++)
    {
        if (findOpenSpot(board, row, j, size) == true)
        {
            if (queenNumber >= 0)
            {
                board[row][j] = 'Q';
                cout << "Subtracting one queen." << endl;
            }
            else if (queenNumber < 0)
            {
                board[row][j] = '-'; //If all queens have already been placed, start showing open slots.
            }
            if (nQueenSolver(board, row+1, size, queenNumber) == true) //Recursion to cycle down the rows
            {
                return true; 
            }
            board[row][j] = '.'; //Backtracking if needed.
        }

    }
    return false;
}

bool findOpenSpot(char board[100][100], int row, int col, int size)
{
    int i, j;
    for (i=0; i<col; i++)
    {
        if (board[row][i] == 'Q') //Checks if there's any queens to the left of the index
        {
            return false; //Not an open spot.
        }
    }
    i = row; j = col;
    while (i >= 0 && j >= 0)
    {
        if (board[i][j] == 'Q') //Checks if there's any queens in the upper left diagonal of the index
        {
            return false; 
        }
        i--; j--;
    }

    for (i=0; i<row; i++)
    {
        if (board[i][col] == 'Q') //Checks if there's any queens on top of the index
        {
            return false; 
        }
    }

    i = row; j = col;
    while (i >= 0 && j >= 0)
    {
        if (board[i][j] == 'Q') //Checks if there's any queens in the upper right diagonal of the index
        {
            return false;
        }
        i--; j++;
    }

    return true; //This index isn't threatened by a queen, go ahead and place one here!
    //Open spot!!
}


void readBoard(char board[100][100], int size)
{
    for (int i=0; i<size; i++) //Puts in the size of the board into the array.
    {
        for (int j=0; j<size; j++)
        {
            board[i][j] = '.';
        }
    }
}

void printBoard(char board[100][100], int size)
{
    for (int i=0; i<size; i++) //Prints the 'board' part of the array. (Doesn't print the entire array)
    {
        for (int j=0; j<size; j++)
        {
            cout << board[i][j];
        }
        cout << endl;
    }
}

Я также пытался искать помощь в Интернете и ничего не нашел (как в stackoverflow, так и в Google. Только фрагменты информации, которые я уже использовал). Любая помощь будет принята с благодарностью! :)


person auradun    schedule 30.03.2018    source источник


Ответы (1)


Ваша проверка "вверху справа" в findOpenSpot (последний цикл while) имеет неверное условие. Поскольку вы увеличиваете j в этом цикле, вам нужно проверить, находится ли j ниже верхней границы массива, а не сравнивать с нулем.

while (i >= 0 && j < size)

Это также будет использовать параметр size, который в настоящее время не используется. Если вы компилируете с достаточно высоким уровнем предупреждений, компилятор сообщит вам, что size является неиспользуемым параметром, что будет подсказкой о том, что что-то не так.

person 1201ProgramAlarm    schedule 30.03.2018