N queen使用c ++并使用动态2D数组进行回溯

时间:2013-10-13 13:44:02

标签: c++ backtracking n-queens

我一直试图用回溯来解决N皇后问题。我在网上找到的大多数方法都涉及向量,这使得我很难将解决方案可视化为互联网上的一些小程序。

我提出的解决方案,给了我很多问题(我有一种感觉与使用的动态2D数组的索引有关)并且我无法使用Dev-C ++调试器解决它。任何帮助和/或建设性的批评受到高度赞赏。提前谢谢了。

以下是我提出的解决方案:

#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();
}

1 个答案:

答案 0 :(得分:1)

它在初始配置后运行,但您不打印它。改变这个(内部解决):

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

为此:

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

除此之外,您进行回溯的方式存在问题。如果没有可用的选项,则从上一行中移除后处理(这没关系),然后将正在攻击的每个单元标记为安全(不正常)。问题是这些细胞中的一些可能受到不同女王的攻击,所以你不能将它们标记为安全。此外,您不要在该行上放置不同的女王。我提出了一些解决方案:

首先,使其递归:considerrow将使用以下行调用自身,如果成功则返回true(1),如果失败则返回false(0)。如果它与下一行失败,你可以使用当前行中的下一个皇后并再次调用considerrow,直到你成功或用完列,在这种情况下你返回false。

要考虑某一行上的不同女王,您可以做两件事:创建一个董事会副本,您将传递给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
}

可以修改回溯功能以恢复当前行,如下所示:

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);
}