gpt4 book ai didi

c++ - 使用 C++ 的 N 皇后和使用动态二维数组的回溯

转载 作者:行者123 更新时间:2023-11-28 07:21:49 26 4
gpt4 key购买 nike

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

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

最佳答案

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

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

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

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

关于c++ - 使用 C++ 的 N 皇后和使用动态二维数组的回溯,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19345908/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com