今天在一次采访中有人问我以下问题,从那以后我一直在思考。我无法回答,也无法在线找到解决方案。
给定一个棋盘尺寸为X乘以Y和N个皇后的棋盘,请确定是否有可能将这些皇后安排在棋盘上,以使它们不会互相攻击。
具有2个皇后的2 x 3电路板确实有解决方案,因此算法将返回true:
Q . .
. . Q
我正在寻找一种解决这个难题的编程方法,例如,不仅仅是纸上解决难题的方法。
今天在一次采访中有人问我以下问题,从那以后我一直在思考。我无法回答,也无法在线找到解决方案。
给定一个棋盘尺寸为X乘以Y和N个皇后的棋盘,请确定是否有可能将这些皇后安排在棋盘上,以使它们不会互相攻击。
具有2个皇后的2 x 3电路板确实有解决方案,因此算法将返回true:
Q . .
. . Q
我正在寻找一种解决这个难题的编程方法,例如,不仅仅是纸上解决难题的方法。
Answers:
从编程的角度来看,这不是(IMO)一个非常有趣的问题。您可以想出一种递归算法来尝试各种排列,如下所示:
bool try_queens(Board board, int n)
{
if (n == 0) {
// no queens left to place, so we're done
return true
}
// try each open position until we find one that works
for each position on the board {
if (is_empty(board, position) and not is_attacked(board, position)) {
place_queen(board, position)
if (try_queens(board, n-1)) {
return true
}
remove_queen(board, position)
}
}
// if we get this far, there's no available position
return false
}
main()
{
initialize board(X,Y)
return try_queens(board, N)
}
如果您稍微考虑一下问题,您会意识到无法将N个皇后装在X <N或Y <N的板上,因为这将需要至少两个皇后以相同的等级或档位结束,因此他们会互相攻击。如果您读过n皇后问题,您将很快了解到,对于N> 3,总是可以将N个皇后放在NxN板上。现在,我们知道答案是否定的(X <N或Y <N) (X> = N并且Y> = N,N> 3)为是。剩下的就是特殊情况:
因此,现在我们不错的递归函数变成了一个简单的函数,它仅将N与X和Y进行比较并返回固定结果。从性能的角度来看,这是很棒的,因为您可以在固定时间内获得答案。从编程的角度来看并不是那么好,因为在这一点上,您意识到真正的问题更多是关于如何解决难题的问题,而不是关于编写递归函数的能力。
(天哪,天哪,我真的希望我在聪明的裤子回答中不要犯一些愚蠢的错误。;-)
That's great from a performance point of view, since you can get an answer in constant time. It's not so great from a programming point of view because you realize, at this point, that the question is really more about how well you can solve puzzles than it is about your ability to write a recursive function.
我实际上认为面试官正在等待O(1)解决方案,因为它最终会更好,而且对许多人来说并不明显。在所有编程课程中,nxn皇后问题都作为递归的练习-许多人在再次看到该问题时不会更深入地思考。
如果面试官要求您为该问题编写代码,那么我认为这是不公平的。该算法需要工作。但是,如果您的想法是向面试官展示您需要使用的类,方法或某些概念或类似的东西,那么这可能是一个公平的问题。
该问题是经典的计算机科学问题,许多此类书籍都对此进行了讨论。在这里可以找到很好的解释,其中包含动画和12种不同的解决方案以及一些代码:
http://en.wikipedia.org/wiki/Eight_queens_puzzle
也可以在这里找到代码:http : //www.codeproject.com/KB/java/EightQueen.aspx
正如我所说,不要为此感到难过,这不是一件容易的事。
确实,这更多是评论,但不适合其中...
一个国际象棋棋盘有8x8的正方形,且不少于8个(这些问题总是用定制的国际象棋棋盘的方法使我烦恼)。
但是无论如何,如果您有一个x * y的棋盘,并且有n个皇后,并以皇后“占领” 这些字段
您能否创建一个二维数组并“标记”一位女王攻击的所有字段。然后放置另一个(从板子中间开始),标记其余字段,依此类推……直到您运行任何一个字段或皇后区。
当然,这是一种非常简化的方法,因为如果定位不正确,我收集到的皇后数量将有所不同。
嗯,刚才也发现了-8个皇后问题。
基本上,回溯算法的工作原理如下:
创建一个X by Y数组。将所有正方形设置为空。
将女王计数设置为零。
将当前位置设置为(1,1)
看看是否可以在当前位置放置一个女王。
如果可以,请将Array(X,Y)设置为皇后,增加皇后计数。如果放置了所有皇后,请停止,您有解决方案。
如果当前位置不是(X,Y),则增加当前位置并转到步骤4。
在最后一个位置找到皇后(按照增加位置的顺序最后一个)。将当前位置设置为该皇后的位置,将其删除,然后减少皇后计数。
如果皇后计数为零,请停止,没有解决方案。
增加当前位置。
转到步骤4。
除其他答案外:创建二维数组只会使代码复杂化。
您只需要一个大小为8的向量即可构成一个普通的棋盘。如果像C 1st位是0,则为8 + 1,只是为了简化代码,而处理1-8而不是0-7。
如果您认为x是您在数组中的位置,而y是该位置的内容。例如board [1] = 8表示第一个皇后在[1,8]。
这样,您只需要检查列验证即可。
在上大学的时候,我遇到了一本非常古老的书(60年代?),它讲述了在Dartmouth BASIC中实现的算法,该书使用了尽可能少的内存来实现8皇后问题(因为年代久远,很有意义)。
据我所记得,它使用了向量思想,并且本质上以两个FOR循环强行强制执行板上的所有位置。为了检查位置的有效性,它使用了第三个循环,每个位置的WHILE循环都返回到向量中,并检查是否相等,或者使用切线运算的公式检查对角线。
可悲的是,我忘了那本书。
所述算法找到了n-queen问题的所有解。
如果您只需要编写一种算法来确定是否存在这种安排,那么请看一下现有的研究:
Wikipedia上的八个皇后难题。
如果N> min(X,Y),则可以简单地返回false。
阅读该页面后,您知道如果N <= min(X,Y)和2,3!= min(X,Y),则返回true。
剩下2、3 == min(X,Y)和N <= min(X,Y)。
好吧,如果N <min(X,Y),找到一个解决方案很简单。
如果N == min(X,Y),则只有max(X,Y)> N时才有解决方案。
f(X, Y, N)
if X < Y => f(Y, X, N)
if Y > N => false
=> (Y < N) or (Y != 2 and Y != 3) or (X > N)
如果N> min(X,Y),显然没有解决方案。否则,您可以轻松地显示出对于N = X = Y = 2,N = X = Y = 3没有解决方案。对于所有其他情况,似乎都有解决方案。解决方案的数量似乎随着N的增加而增加。
您可以通过带回溯的详尽搜索找到解决方案:在第一行第一列中放置一个女王/王后,在第一行中女王/王后无法到达的第一列中/第二王后。在第二行等中放置一个女王/王后。如果不能将女王/王后放入k行,则将其删除,然后将k-1行中的女王/王后移至下一个未占用位置。