js实现八皇后,回溯法
八皇后问题:将八个皇后摆在一张8*8的国际象棋棋盘上,使每个皇后都无法吃掉别的皇后,一共有多少种摆法?
两个皇后不能同时在同一行,同一列,和斜对角线的位置上,使用回溯法解决。
从第一行选个位置开始放棋子,第二行从0开始选择满足规则的位置,到第三行发现没有位置可以满足规则,那么就把第二行的棋子向后移动一个可以满足规则的位置,如果没有这个位置,就返回到第一行,将棋子向后移动一个,从头开始,以此类推。
这个同学的博客讲的很通俗易懂 https://www.cnblogs.com/bigmoyan/p/4521683.html
1、首先尝试使用嵌套for循环实现,发现只能找出第一种解法,没办法统计到所有的解法
var n = 8 ;
var arr = [];
var total = 0; function b() { for (var row = 0; row <= n;) { if (row == n) { total++; break; } else { var col = 0; if (arr[row] != undefined) {
//说明是回溯回来重新选择位置的,要从上次的位置开始往后选 var col = arr[row] + 1; } for (; col <= n; col++) { if (col == n) {
//当前行的所有列都走完了,都没有位置可以放棋子,则从上一行开始从新选择位置 arr[row] = undefined; row--; if (row) break; } if (isOk(row, col)) { arr[row] = col; row++; break; } } } } } function isOk(row, col) { for (var i = 0; i < row; i++) { if (row == 0) {
//第一行随便放哪个位置都行 return true; } if (arr[i] == col || Math.abs(arr[i] - col) == Math.abs(i - row)) {
//同一行,同一列或者斜对角线都不能放 return false; } } return true; } b(); console.info(total);
for循环太复杂了,当找到一个解法后,希望移动第一行的棋子,寻找其他解法时,这个时候,当回溯到第一行时,无法控制棋子的位置(比如已经从第0个位置移到2位置才寻找到了第一种解法,当寻找其他解法时,回溯到第一行时,就不应该在返回都0,1这个两个位置),for循环无法记录。
转用递归实现,此时每一行的for循环都能被记住当前是第几列
var arr = []; var total = 0; var arr2=[]; function ab(row){ if(row == n){ //当row已经成功走到最后一行,说明已经找到了一种解法 arr2.push([].slice.call(arr));//找到一种解法,就把当前的位置记录下来 total++; } for(var col=0;col<n;col++){ if(isOk(row,col)){ //当前行的这一列不与前几行的位置冲突,则把这个位置记录下来,位置记录下来,是为了每次循环比较是否有冲突 arr[row]=col; ab(row+1);//进入下一行选位置,因为递归,所以当里层的循环全部结束以后,会返回上一层继续循环,实现了回溯 } } } function isOk(row, col) { for (var i = 0; i < row; i++) { //从第0行开始比较和当前的位置是否有冲突 if (row == 0) { return true; } if (arr[i] == col || Math.abs(arr[i] - col) == Math.abs(i - row)) { return false; } } //成功比较完了之前的所有行,说明这个位置可以放置 return true; } ab(0); console.info(total); console.info(arr2);