如何在 N-Queen 问题中跳过重复的棋盘状态?
Posted
技术标签:
【中文标题】如何在 N-Queen 问题中跳过重复的棋盘状态?【英文标题】:How can I skip duplicate board states in N-Queen problem? 【发布时间】:2020-03-20 17:39:10 【问题描述】:我编写了一些运行良好的代码,除了它还发现了重复的板状态。我希望对我的代码进行最小的更改,以便它只能找到唯一的板状态。我在下面粘贴我的代码:
class Solution
List<List<String>> arrangements = new ArrayList<>();
public List<List<String>> solveNQueens(int n)
int visited[][] = new int[n][n];
char board[][] = new char[n][n];
solve(board,visited,0);
return arrangements;
public boolean solve(char board[][], int visited[][], int queens)
if(queens == board.length)
return true;
for(int i = 0; i < board.length; i++)
for(int j = 0; j < board.length; j++)
if(visited[i][j] == 0)
changePosition(visited,i,j,1); //set
board[i][j] = 'Q';
if(solve(board,visited,queens+1))
save(board);
changePosition(visited,i,j,-1); // unset
board[i][j] = '.';
return false;
public void save(char board[][])
List<String> state = new ArrayList<>();
for(int i = 0; i < board.length; i++)
String row = "";
for(int j = 0; j < board.length; j++)
if(board[i][j] == 'Q')
row += 'Q';
else
row += '.';
state.add(row);
arrangements.add(state);
public void changePosition(int visited[][], int i, int j, int val)
// setting the column
for(int k = 0; k < visited.length; k++)
visited[k][j] += val;
visited[i][j] -= val;
//setting the row
for(int k = 0; k < visited.length; k++)
visited[i][k] += val;
visited[i][j] -= val;
//setting 1 diagonal
int a = i, b = j;
while(a < visited.length && b < visited.length)
visited[a][b] += val;
a++;
b++;
visited[i][j] -= val;
a = i;
b = j;
while(a >= 0 && b >= 0)
visited[a][b] += val;
a--;
b--;
visited[i][j] -= val;
//setting 2nd diagonal
a = i;
b = j;
while(a < visited.length && b >= 0)
visited[a][b] += val;
a++;
b--;
visited[i][j] -= val;
a = i;
b = j;
while(a >=0 && b < visited.length)
visited[a][b] += val;
a--;
b++;
函数solveNQueens
以List
的形式返回所有有效的棋盘状态(用String
表示的行的List
表示的棋盘状态)。提前致谢!
【问题讨论】:
【参考方案1】:您的代码的问题在于,对于每个皇后,您都尝试了所有可能的棋盘位置。这意味着对于n
皇后,每个解决方案都将重复n!
次(n
皇后可以在解决方案中的皇后位置之间排列的次数)。
我们可以从您的程序为每个 n
(reference) 找到的解决方案数量中看出这一点:
n=4
:有2
解决方案,但您的程序找到48 = 2*4! = 2*24
解决方案。
n=5
:有10
解决方案,但您的程序找到1200 = 10*5!=10*120
解决方案。
n=6
:有4
解决方案,但您的程序找到2880 = 4*6! = 4*720
解决方案。
...
这很容易解决:不要为每个皇后尝试所有可能的棋盘位置,而是将每个皇后限制在一个固定的列中,并且只尝试该列中的位置。这样就不会找到重复的棋盘位置了。
在您的solve
方法中,删除内部for
循环,而是将j
坐标设置为女王的编号(意味着女王0 将在第0 列,女王1 将在第1 列,等等):
public boolean solve(char board[][], int visited[][], int queens)
if (queens == board.length)
return true;
for (int i = 0; i < board.length; i++)
int j = queens;
...
【讨论】:
以上是关于如何在 N-Queen 问题中跳过重复的棋盘状态?的主要内容,如果未能解决你的问题,请参考以下文章