验证 N 皇后问题的解决方案
Posted
技术标签:
【中文标题】验证 N 皇后问题的解决方案【英文标题】:validating a solution for N queen problem 【发布时间】:2018-12-03 07:51:46 【问题描述】:我正在尝试编写一个函数来获得一个 MxN 大小的板,其中有一列和一行放置一个皇后。然后我想看看那个女王是否受到威胁。 通常我会拿那行并检查它是否有任何其他皇后,对于列和对角线使用 for 循环也是如此。 但是这里有一个细微的变化,棋盘上还有一些墙可以保证皇后的安全,即使同一行还有另一个皇后:
* * Q X * Q
* * X * * *
* Q X X Q *
Q * X Q Q *
其中 Q 是皇后,X 是墙,* 是空瓷砖。 位于 0,2 位置的皇后不会受到威胁,即使该行还有另一个。
整个棋盘也保存在一个二维数组中,其中皇后的 int 值为 1,墙为 -1,空白为 0。
我的想法是遍历整个行,如果某处有一个皇后,那么我应该寻找一堵墙,从那个位置到我正在看的皇后有另一个 for 循环。但是在我的女王之后还有第二部分。
我尝试考虑求和,但也不太奏效.. 有人对如何实现这一点有任何想法吗? (如果受到威胁,则返回 true;如果没有受到威胁,则返回 false;)
编辑:这是我的代码
`public static boolean isQueenThreatened(int[][] board, int row, int col)
boolean safe=true;
for(int j = 0; j < col & safe ; j++)
if(board[row][j]==1)
for (int i = j+1 ; i<col ; i++ )
if(board[row][i]!=-1) safe = false;
for(int j = col+1; j < board[row].length & safe ; j++)
if(board[row][j]==1)
for (int i = j+1 ; i<board[row].length ; i++ )
if(board[row][i]!=-1) safe = false;
return safe;
`
所以函数获取了皇后的位置(假设它是有效的),然后我想遍历那一排直到我的皇后和之后,看看是否有其他皇后,如果有我想检查是否有它们之间的墙是为了保证我的女王的安全,显然我的不起作用,因为如果它们之间只有一堵墙,它会给出错误的结果,只有一堵墙就足够了,不一定是所有的墙。
* Q * * X Q' * X Q
我用'表示我的女王,我的代码会为那个例子返回假,即使它应该是真的..然后我必须对对角线和列做同样的事情..这就是我需要的地方帮助。
【问题讨论】:
您有问题吗? 是的。如果有任何想法如何使我的想法发挥作用?如何有效地越过这一行,看看女王是否受到威胁,因为我不能仅仅决定它的右边是否有墙是安全的,因为它的左边可能有一个女王,或者根本没有女王而且没有墙,而且它仍然是安全的 如果您显示您正在尝试的代码以及哪里出了问题,您会更好地得到答案。 我已经添加了我的代码 【参考方案1】:这是与Iterator
s 合作的绝佳机会。
static class Board
private final int width;
private final int height;
private final int[][] board;
private static final int EMPTY = 0;
private static final int WALL = -1;
private static final int QUEEN = 1;
public Board(int width, int height)
this.width = width;
this.height = height;
board = new int[height][width];
public Board(String[] setup)
this(setup[0].length(), setup.length);
for (int y = 0; y < setup.length; y++)
for (int x = 0; x < setup[y].length(); x++)
switch (setup[y].charAt(x))
case '*':
board[y][x] = EMPTY;
break;
case 'X':
board[y][x] = WALL;
break;
case 'Q':
board[y][x] = QUEEN;
break;
public Iterator<Integer> walk(int xStart, int yStart, int dx, int dy)
return new Iterator<Integer>()
int x = xStart;
int y = yStart;
@Override
public boolean hasNext()
return x + dx < width && y + dy < height
&& x + dx >= 0 && y + dy >= 0;
@Override
public Integer next()
return board[y += dy][x += dx];
;
public int get(int x, int y)
return board[y][x];
enum Direction
NORTH(0, -1),
NORTH_WEST(1, -1),
WEST(1, 0),
SOUTH_WEST(1, 1),
SOUTH(0, 1),
SOUTH_EAST(-1, 1),
EAST(-1, 0),
NORTH_EAST(-1, -1),
;
private final int dx;
private final int dy;
Direction(int dx, int dy)
this.dx = dx;
this.dy = dy;
public static boolean isQueenThreatened(Board board, int row, int col)
for (Direction direction : Direction.values())
walk: for (Iterator<Integer> attack = board.walk(col, row, direction.dx, direction.dy); attack.hasNext(); )
switch (attack.next())
case Board.QUEEN:
return true;
case Board.WALL:
break walk;
return false;
private void test()
String[] test = new String[]
"**QX*Q",
"**X***",
"*QXXQ*",
"Q*XQQ*"
;
Board board = new Board(test);
for (int y = 0; y < board.height; y++)
for (int x = 0; x < board.width; x++)
if (board.get(x, y) == Board.QUEEN)
System.out.println("Queen at position (" + x + "," + y + ") is " + (isQueenThreatened(board, y, x) ? "" : "NOT") + " threatened");
顺便说一下,(0,2)
你的女王 IS 受到(2,4)
女王的威胁。
【讨论】:
【参考方案2】:对于给定的皇后位置,您需要遍历行、列和每个对角线。在每个方向上,您都可以遵循相同的规则:
-
如果你击中另一个女王,你会受到威胁,返回
true
。
如果你撞到了墙,你在那个方向是安全的,继续下一个检查。
如果您击中了棋盘边缘,那么您在那个方向是安全的,请继续进行下一次检查。
public static boolean isQueenThreatened(int[][] board, int row, int col)
// Go over the row, to the left:
for (int i = col - 1; i >= 0; --i)
int val = board[row][i];
if (val == 1)
return true;
if (val == -1)
break;
// Same logic for:
// - Going over the row to the right
// - Going over the column to the top
// - Going over the column to the bottom
// - Going over the top left diagonal
// - Going over the top right diagonal
// - Going over the bottom left diagonal
// - Going over the bottom right diagonal
// If you reached here, it means that no early return was performed,
// and the queen is safe
return false;
编辑:
要回答 cmets 中的要求,您可以添加额外的 boolean
s 以发现撞墙的威胁,但是 TBH,我认为代码看起来会差很多:
public static boolean isQueenThreatened(int[][] board, int row, int col)
boolean threat = false;
// Go over the row, to the left:
boolean wall = false;
for (int i = col - 1; i >= 0 && !threat && !wall; --i)
int val = board[row][i];
if (val == 1)
threat = true;
if (val == -1)
wall = true;
// Go over the row, to the right.
// Reset the wall variable, as you haven't detected a wall in this direction yet
// The threat potentially found in the previous loop is still present
// so if it still exists, the loop will be skipped
boolean wall = false;
for (int i = col + 1; i < board[row].length && !threat && !wall; ++i)
int val = board[row][i];
if (val == 1)
threat = true;
if (val == -1)
wall = true;
// Same logic for:
// - Going over the column to the top
// - Going over the column to the bottom
// - Going over the top left diagonal
// - Going over the top right diagonal
// - Going over the bottom left diagonal
// - Going over the bottom right diagonal
// If you reached here, it means that no early return was performed,
// and the queen is safe
return threat;
【讨论】:
您知道如何做到这一点而不会中断,也不会提前返回。我的意思是我只会在函数结束时返回一次。我必须这样做,这对我来说有点困难。 @lidorportal 我已经编辑了我的答案并添加了它,但是TBH,我认为在这种情况下使用提前返回和中断会使代码更清晰。以上是关于验证 N 皇后问题的解决方案的主要内容,如果未能解决你的问题,请参考以下文章