所以我需要帮助解决经典的N-Queens问题。
运行程序的命令是: nqueens N k - 其中N是表格的大小(N x N),k是解决方案的数量
例如,如果我通过输入 nqueens 4 1 来运行该程序,则会打印出以下内容。
_ Q _ _
_ _ _ Q
问_ _ _
_ _ Q _
然而,我无法弄清楚如何处理超过1个解决方案?如何为这个问题确定一个以上的解决方案呢?
到目前为止我的内容如下:
#include <cstdlib>
#include <iomanip>
#include <cmath>
#include <vector>
using namespace std;
class Board
{
private:
bool** spaces;
int size;
public:
Board(int size)
{
this->size = size;
spaces = new bool*[size];
for (int i = 0; i < size; ++i)
{
spaces[i] = new bool[size];
}
}
bool isSafe(int row, int column, vector<int>& state)
{
//check row conflict
//no need to check for column conflicts
//because the board is beimg filled column
//by column
for(int i = 0; i < column; ++i)
{
if(state[i] == row)
return false;
}
//check for diagonal conflicts
int columnDiff = 0;
int rowDiff = 0;
for(int i = 0; i < column; ++i)
{
columnDiff = abs(column - i);
rowDiff = abs(row - state[i]);
if(columnDiff == rowDiff)
return false;
}
return true;
}
int getSize()
{
return size;
}
bool getSpace(int x, int y)
{
return spaces[y][x];
}
void setSpace(int x, int y, bool value)
{
spaces[y][x] = value;
}
Board(Board& other)
{
this->size = other.getSize();
spaces = new bool*[size];
for (int i = 0; i < size; ++i)
{
spaces[i] = new bool[size];
for (int j = 0; j < size; ++j)
{
spaces[i][j] = other.getSpace(j, i);
}
}
}
void backtrack(vector<int>& state, int board_size)
{
int row = 0;
int column = 0;
bool backtrack = false;
while(column < board_size)
{
while(row < board_size)
{
if(backtrack)
{
row = state[column] + 1;
if(row == board_size)
{
column--; //backtrack more
backtrack = true;
row = 0;
break;
}
backtrack = false;
}
if(isSafe(row, column, state))
{
state[column] = row;
row = 0;
column++; //advance
backtrack = false;
break;
}
else
{
if(row == (board_size - 1))
{
column--; //backtrack
backtrack = true;
row = 0;
}
else
{
row++;
}
}
}
}
}
};
int print_solutions(Board *board, vector<int>& state, int board_size)
{
for(int i=0; i < board_size; ++i)
{
for(int j=0; j < board_size; ++j)
{
if(state[i] == j)
cout << 'Q' << " ";
else
cout << '_' << " ";
}
cout << endl;
}
}
int main(int argc, char* argv[])
{
if (argc < 2)
{
cout << "Usage: nqueens [Board Size] [Number of Solutions]" << endl;
return 1;
}
int board_size = atoi(argv[1]);
//int solution_count = atoi(argv[2]);
vector<int> state;
state.resize(board_size);
Board *my_board = new Board(board_size);
my_board->backtrack(state, board_size);
print_solutions(my_board, state, board_size);
return 0;
}
答案 0 :(得分:2)
在这个解决方案中,我保留了原始方法和代码:
#include <cstdlib>
#include <iomanip>
#include <cmath>
#include <vector>
#include <iostream>
using namespace std;
class Board
{
private:
bool** spaces;
int size;
public:
Board(int size)
{
this->size = size;
spaces = new bool*[size];
for (int i = 0; i < size; ++i)
{
spaces[i] = new bool[size];
}
}
bool isSafe(int row, int column, vector<int>& state)
{
//check row conflict
//no need to check for column conflicts
//because the board is beimg filled column
//by column
for(int i = 0; i < column; ++i)
{
if(state[i] == row)
return false;
}
//check for diagonal conflicts
int columnDiff = 0;
int rowDiff = 0;
for(int i = 0; i < column; ++i)
{
columnDiff = abs(column - i);
rowDiff = abs(row - state[i]);
if(columnDiff == rowDiff)
return false;
}
return true;
}
int getSize()
{
return size;
}
bool getSpace(int x, int y)
{
return spaces[y][x];
}
void setSpace(int x, int y, bool value)
{
spaces[y][x] = value;
}
Board(Board& other)
{
this->size = other.getSize();
spaces = new bool*[size];
for (int i = 0; i < size; ++i)
{
spaces[i] = new bool[size];
for (int j = 0; j < size; ++j)
{
spaces[i][j] = other.getSpace(j, i);
}
}
}
bool backtrack(vector<int>& state, int& column, int board_size)
{
int row = 0;
bool backtrack = column == board_size;
while(column < board_size || backtrack)
{
{
if(backtrack)
{
if (column == 0)
return false;
column--;
row = state[column] + 1;
if(row == board_size)
{
backtrack = true;
continue;
}
backtrack = false;
}
if(isSafe(row, column, state))
{
state[column] = row;
row = 0;
column++; //advance
backtrack = false;
continue;
}
else
{
if(row == (board_size - 1))
{
backtrack = true;
}
else
{
row++;
}
}
}
}
return true;
}
};
void print_solutions(Board *board, vector<int>& state, int board_size)
{
for(int i=0; i < board_size; ++i)
{
for(int j=0; j < board_size; ++j)
{
if(state[i] == j)
cout << 'Q' << " ";
else
cout << '_' << " ";
}
cout << endl;
}
cout << endl;
}
int main(int argc, char* argv[])
{
if (argc < 3)
{
cout << "Usage: nqueens [Board Size] [Number of Solutions]" << endl;
return 1;
}
int board_size = atoi(argv[1]);
int solution_count = atoi(argv[2]);
vector<int> state;
state.resize(board_size);
Board *my_board = new Board(board_size);
int column = 0;
while (solution_count-- > 0 && my_board->backtrack(state, column, board_size))
print_solutions(my_board, state, board_size);
return 0;
}
#include
iostream print_solutions
中的额外换行符以分隔多个解决方案print_solutions
已打印转置表print_solutions
未返回值 - &gt; void
argc
检查solution_count
移至呼叫网站column
支持
column--
,row = 0
)row < board_size
)my_board
泄露Board
类及其实例是不必要的答案 1 :(得分:2)
这是我的蛮力递归解决方案。它不是最佳选择(无回溯),但对于14 x 14以下的国际象棋棋盘来说,效果很好。
在递归方法queensSolution
中,第一个参数是棋盘的大小。第二个参数编码皇后区的实际位置。
例如,描述图片上位置的矢量将是{1、3、0、2}。这意味着:在第一行(计数从0开始,因此它是向量的第一个元素)中有一个皇后在位置1(从左数第二个平方)上,在第二行(向量中的第二个元素)中有一个皇后在位置3(该行的最后一个四边形)上等等。
第三个参数包含将包含所有解位置的向量(如上所述,被编码为向量)。
帮助方法intersect
检查将放置在位置{queens.size(),x}上的新皇后之间是否存在冲突。当新女王/王后与任何现有女王/王后位于相同的“列”(x位置)或新女王/王后与任何现有女王/王后的x位置和y位置之间的距离相等(对角位置)时,就会发生冲突。我们不必检查是否将新皇后放置在已经放置了其他皇后的行(y)中,因为每次将元素添加到queens
向量中时,我们都会将其放置在新行中。 / p>
#include<vector>
using namespace std;
bool intersect(const vector<int> &queens, int x) {
int y = queens.size();
for (int i = 0; i < y; i++) {
if ((abs(queens[i] - x) == 0) || (abs(queens[i] - x) == y - i))
return true;
}
return false;
}
void queensSolution(const int dim, vector<int> queens, vector<vector<int>> &res) {
if (queens.size() >= dim) {
res.push_back(queens);
queens.clear();
return;
}
for (int i = 0; i < dim; i++) {
if (!intersect(queens, i)) {
queens.push_back(i);
queensSolution(dim, queens, res);
queens.pop_back();
}
}
}
例如,要查找4 x 4棋盘的所有解决方案,请执行以下操作:
int main(){
int dim = 4;
vector<int>queens;
vector<vector<int>> result;
queensSolution(dim, queens, result);
}
queensSolution
返回后,向量结果包含两个向量:{1, 3, 0, 2}
和{2, 0, 3, 1}
。
答案 2 :(得分:1)
您可以使用递归方法来解决它。我写了一篇关于此的文章:Recursion tutorial: N-queens in C。要获得所有解决方案,只需运行递归而不终止找到第一个解决方案。
此处还有一个启发式解决方案:Eight queen puzzle。
答案 3 :(得分:0)
检查gist。它是一个简单的递归函数,返回所有解决方案。
它的工作原理是每次将一个女王放在下一行。方法is_safe
检查在下一行的列col放置一个女王是否安全。解决方案是vector,其中索引i是行,而该索引处的值是列。每次成功放置后,向量增长一个元素并添加到候选解决方案集中,这些候选解决方案在递归调用堆栈中返回。