N Queen с использованием C ++ и возврат с помощью динамического 2D-массива

0

Я пытался решить проблему N queen, используя backtracking. Большинство подходов, которые я нашел в Интернете, связаны с переносчиками, что затрудняет визуализацию решений, как это делают некоторые апплеты в Интернете.

Решение, которое я придумал, дает мне много проблем (у меня есть чувство связано с индексацией динамического 2D-массива), и я не могу понять это с помощью отладчика Dev-С++. Любая помощь и/или конструктивная критика высоко ценится. Спасибо заранее.

Вот решение, с которым я столкнулся:

#include<iostream>
#include<string.h>
#include<conio.h>

using namespace std;

void display(char** b, int len);
void initialize(char** &b, int k);
void consider1strow(char ** b, int len);
void markunsafe(char** board, int rowno, int colno);
void marksafe(char** board, int rowno, int colno);
void considerrow(char** board, int rowno);
void backtrack(char** board, int rowno);
bool checksafety(char** board, int rowno, int colno);
void place(char** board, int rowno, int colno);
void solve(char** board, int len);


int state[20] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
int len;

void display(char** board, int len)
{
    int i, j;
    cout << endl << "The current state of the board:" << endl;
    for (i = 0; i < len; i++)
    {
        for (j = 0; j < len; j++)
        {
            cout << board[i][j];
        }
        cout << endl;
    }
}

void initialize(char** &b, int k)
{

    int i, j;

    //create dynamic board
    b = new char*[k];
    for (i = 0; i < k; i++)
    {
        b[i] = new char[k];
    }

    //initialize array
    for (i = 0; i < k; i++)
    {
        for (j = 0; j < k; j++)
        {
            b[i][j] = '-';
        }
    }

}

void consider1strow(char ** board, int len)
{
    int col;
    cout << "Enter the column to try for the first row!";
    cin >> col;
    board[0][col - 1] = 'Q';
    state[0] = col - 1;
    markunsafe(board, 0, col - 1);
    display(board, len);
}

void markunsafe(char** board, int rowno, int colno)
{
    int i, j;

    //mark row as unsafe
    for (i = 0; i < len; i++)
    {
        board[rowno][i] = 'x';
    }

    //mark column as unsafe
    for (i = 0; i < len; i++)
    {
        board[i][colno] = 'x';
    }

    //mark unsafe diagonals
    for (i = 0; i < len; i++)
    {
        for (j = 0; j < len; j++)
        {
            if ((rowno + colno) == (i + j))
            {
                board[i][j] = 'x'; //check if index gives a problem of +/- 1 
            }
            if ((rowno - colno) == (i - j))
            {
                board[i][j] = 'x';  //check if index gives a problem of +/- 1
            }
        }
    }
    board[rowno][colno] = 'Q';

}

void marksafe(char** board, int rowno, int colno)
{
    int i, j;

    //mark row as safe
    for (i = 0; i < len; i++)
    {
        board[rowno][i] = '-';
    }

    //mark column as unsafe
    for (i = 0; i < len; i++)
    {
        board[i][colno] = '-';
    }

    //mark unsafe diagonals
    for (i = 0; i < len; i++)
    {
        for (j = 0; j < len; j++)
        {
            if ((rowno + colno) == (i + j))
            {
                board[i][j] = '-'; //check if index gives a problem of +/- 1 
            }
            if ((rowno - colno) == (i - j))
            {
                board[i][j] = '-';  //check if index gives a problem of +/- 1
            }
        }
    }
}


void considerrow(char** board, int rowno)
{
    bool safe = 0;
    int i;

    for (i = 0; i < len; i++)
    {
        safe = checksafety(board, rowno, i);
        if (safe && (i >= state[rowno]))
        {
            break;
        }
    }
    if (safe && (i >= state[rowno]))
    {
        place(board, rowno, i);
    }
    else if (!safe)
    {
        backtrack(board, rowno);
    }
}

void backtrack(char** board, int rowno)
{
    marksafe(board, rowno - 2, state[rowno - 2]);
    considerrow(board, rowno);
}

bool checksafety(char** board, int rowno, int colno)
{
    if (rowno == 0)
    {
        return 1;
    }
    else if (board[rowno][colno] == 'x')
    {
        return 0;
    }
    else if (board[rowno][colno] == '-')
    {
        return 1;
    }
}


void place(char** board, int rowno, int colno)
{
    board[rowno][colno] = 'Q';
    state[rowno] = colno;
    markunsafe(board, rowno, colno);
}

void solve(char** board, int len)
{
    int i = 0;
    if (i == len)
    {
        display(board, len);
    }
    else
    {
        consider1strow(board, len);
        for (i = 1; i < len; i++)
        {
            considerrow(board, i);
        }
    }
}

int main()
{
    char** board;
    cout << "Enter the size of the board!";
    cin >> len;
    initialize(board, len);
    solve(board, len);
    getch();
}
Теги:
backtracking
n-queens

1 ответ

1
Лучший ответ

Он запускается после начальной настройки, но вы его не печатаете. Измените это (внутреннее решение):

for(i=1;i<len;i++)
{considerrow(board,i);}

для этого:

for(i=1; i<len; i++) {
      considerrow(board,i);
      display(board,len);
 }

Кроме того, существует проблема с тем, как вы делаете откат. Если параметры не доступны, вы удаляете королеву из предыдущей строки (это нормально), а затем вы отмечаете каждую ячейку, на которую он атаковал как безопасный (не нормально). Проблема в том, что некоторые из этих ячеек могут подвергаться атаке другой королевы, поэтому вы не можете отметить их как безопасные. Кроме того, вы не ставите другую королеву в эту строку. Я предлагаю некоторые решения:

Во- первых, сделать его рекурсивным: considerrow бы называть себя со следующей строки, и возвращает истину (1), если она успешно или ЛОЖЬ (0), если он выходит из строя. Если это не удается с следующей строки, вы можете использовать следующую королеву в текущей строке и вызовите considerrow снова, пока не удастся или запустить из столбцов, в этом случае вы возвращаетесь ложь.

Чтобы рассмотреть другую королеву в определенной строке, вы можете сделать две вещи: создать копию доски, которую вы передадите, чтобы considerrow следующую строку (и, таким образом, сохранить копию "до", чтобы попробовать другую королеву) или отметить каждая ячейка является безопасной, а затем проверяйте всех существующих ферзей, чтобы маркировать ячейки небезопасными.

Редактировать:

Чтобы сделать это рекурсивно, мы собираемся сделать considerrow называть себя следующее значение.

bool considerrow(char** board,int rowno) {
    //Print the board
    display(board,len);
    bool safe=0;
    int i;

    for(i=0; i<len; i++) {
        safe=checksafety(board,rowno,i);
        if(safe) {
            place(board,rowno,i);
            //Is this the last row? If so, we suceeded
            if (rowno==len-1) return 1;
            //Call itself with next row, check if suceeded
            if (considerrow(board,rowno+1))
                return 1;
            else //Failed, try a different row
                backtrack(board,rowno);
        }
    }
    return 0; //If we got here, then we ran out of colums. Return failure
}

Функция backtrack может быть изменена, чтобы вернуть текущую строку следующим образом:

void backtrack(char** board, int rowno) {
    //Clear the current row
    marksafe(board,rowno,state[rowno]);
    //Check that every cell attacked by another queen is marked unsafe
    for(int i=0; i<rowno; i++) markunsafe(board,i,state[i]);
}

Для этого нужно решить только одну строку:

void solve(char** board,int len) {
    considerrow(board,0);
    display(board,len);
}
  • 0
    Это было так глупо с моей стороны! Спасибо за указание на это! Не могли бы вы подробнее рассказать мне о рекурсивной части функции considerrow() ? Еще раз спасибо!
  • 0
    @IshaanSharma Готово. Проверьте изменение моего ответа
Показать ещё 2 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню