【问题标题】:N queen using c++ and backtracking using a dynamic 2D array使用 C++ 的 N 皇后和使用动态 2D 数组的回溯
【发布时间】:2013-10-13 13:44:02
【问题描述】:

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

我想出的解决方案给我带来了很多问题(我觉得这与使用的动态二维数组的索引有关)我无法使用 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();
}

【问题讨论】:

  • “给我带来了很多问题” 比如什么“没有解决方案”?
  • 是的!打印初始配置和不安全块后它不会运行!

标签: c++ backtracking n-queens


【解决方案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)。如果下一行失败,你可以使用当前行的下一个queen并再次调用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]);
}

这样做,solve 只需要调用第一行:

void solve(char** board,int len) {
    considerrow(board,0);
    display(board,len);
}

【讨论】:

  • 我太笨了!谢谢你指出!您能否详细介绍一下considerrow() 的递归部分?再次感谢!
  • 非常感谢@memo1288!你是救世主!我今天明白了以前从未做过的事情!多亏了你!
  • 又遇到了一些调试问题!你能帮忙吗?
猜你喜欢
  • 1970-01-01
  • 2013-02-02
  • 1970-01-01
  • 1970-01-01
  • 2020-06-22
  • 2013-12-27
  • 2020-10-17
  • 1970-01-01
  • 2020-07-04
相关资源
最近更新 更多