有人可以给我一些关于我的java程序的提示或指导吗?我被困在了回溯的想法上。这是代码。如果你看一下方法solve(),它会递归调用自己,但是我陷入了无法放置更多皇后并试图回溯的地步。
public NQueens(int N)
{
this.N = N;
board = new boolean[N][N];
solved = solve(N);
if(solved == true)
{
System.out.println(N+"x"+N+" solution:");
printBoard(N);
}
else
{
System.out.println("There is no solution for "+N+"x"+N+" board");
}
}
public boolean solve(int waitingQueens)
{
if(waitingQueens == 0) return true;
for(int row = 0; row < N; row++)
{
for(int column = 0 ; column < N ; column++)
{
if(isValid(row, column))
{
board[row][column] = true;
waitingQueens--;
boolean solved = solve(waitingQueens);
if(!solved)
{
board[row][column] = false;
solved = solve(waitingQueens);
}
return solved;
}
}
}
return false;
}
public boolean isValid(int rowParam, int columnParam)
{
for(int x = 0; x < N; x++)
{
for(int y = 0; y < N; y++)
{
if(board[x][y] == true) //find the already placed queens on the board and check if the queen about to be placed is on a valid position
{
if(x == rowParam) //check the validity of the row
return false;
if(y == columnParam) //check the validity of the column
return false;
if(Math.abs(x-rowParam) == Math.abs(y-columnParam)) //check the validity of the diagonals
return false;
}
}
}
return true;
}
public void printBoard(int printParam)
{
for(int x1 = 0; x1 < printParam; x1++)
{
for(int y1 = 0; y1 < printParam; y1++)
{
if(board[x1][y1] == true)
{
System.out.print("Q ");
}
else{
System.out.print("* ");
}
}
System.out.println();
}
System.out.println();
}
答案 0 :(得分:3)
我认为这是您尝试实施的算法:假设您已经在主板上拥有M
个皇后(它看起来像M
= N - waitingQueens
或其他东西)。然后,你找到你可以放置女王的每个空方块。如果在那里放置女王是有效的,则将board
中的方块设置为true
,然后递归调用solve
以查看是否可以放置waitingQueens-1
个更多的女王。
您最大的问题在于,如果递归solve
返回false
会发生什么。假设它是4x4电路板而waitingQueens
是4.您将放置第一个女王,然后使用solve
拨打waitingQueens=3
。但是假设它说没有解决方案。然后你这样做:
if(!solved)
{
board[row][column] = false;
solved = solve(waitingQueens);
}
这会将方块设置为false
,这意味着该板现在再次为空。但是,您使用solve(waitingQueens)
致电waitingQueens=3
,这意味着您的递归solve
现在将寻找一个只有3个皇后的解决方案。这不可能是对的。将waitingQueens
重新递增回4将导致无限递归,因为solve(4)
将使用相同的空板调用solve(4)
。
这里的事情是,你已经处于一个双循环中,它将寻找你可以放置女王的每一个方块。如果你试图把一个女王放在某处并且它没有用(递归调用失败),你删除了女王,但是你让双循环为你找到下一个有效的正方形。你不想做另一个递归调用。因此,应删除上述solve(waitingQueens)
调用。
此外,这需要修复:
waitingQueens--;
boolean solved = solve(waitingQueens);
减少waitingQueens
是一个坏主意,因为如果solve
返回false
,并且您必须返回到下一个循环迭代,waitingQueens
将比这是以前,这是不好的。您可以通过在waitingQueens++
分支中说if (!solved)
来恢复它,但为什么要这么麻烦?单独留下waitingQueens
,并用
boolean solved = solve(waitingQueens-1);
我不确定这两个修复是否足以产生正确的答案,但它们是一个开始。还有一些我想提及的事情,尽管这些只是优化:(1)solve
中的循环甚至不应该看非空的方块。你写它的方式,isValid
如果你给它一个非空的正方形,它将返回false
,但它以迂回的方式这样做。在调用isValid
之前,我可能会检查广场是否为空。 (2)一旦你将M
个皇后放在第0行到M-1
,你的递归调用甚至不应该看那些行,因为我们知道你不能在同一行有两个皇后。如果您查看行M
并且找不到解决方案,您可以立即放弃,因为我们知道正确的解决方案必须在每一行都有一个女王。所以你真的只需要solve
中的一个循环。