八皇后问题
八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例。
该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:
在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,
即:任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。
八皇后问题思路
1.第一个皇后先放第一行第一列
2.第二个皇后放在第二行第一列、然后判断是否OK, 如果不OK,继续放在第二列、第三列、依次把所有列都放完,找到一个合适
3.继续第三个皇后,还是第一列、第二列……直到第8个皇后也能放在一个不冲突的位置,算是找到了一个正确解
4.当得到一个正确解时,在栈回退到上一个栈时,就会开始回溯,即将第一个皇后,放到第一列的所有正确解,全部得到.
5.然后回头继续第一个皇后放第二列,后面继续循环执行 1,2,3,4的步骤
方法check和方法check2的原理其实是一样的,check方法用的是递归实现,check2方法用的是普通for循环实现,
根据排队组合理论
八皇后的放置位置一共有8的8次方个,
每个皇后都有八种放置位置,所以乘起来就是8的8次方个,
check2方法的8个for循环就是这个道理
/*** 八皇后问题八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例。该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即:任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。八皇后问题思路
1.第一个皇后先放第一行第一列
2.第二个皇后放在第二行第一列、然后判断是否OK, 如果不OK,继续放在第二列、第三列、依次把所有列都放完,找到一个合适
3.继续第三个皇后,还是第一列、第二列……直到第8个皇后也能放在一个不冲突的位置,算是找到了一个正确解
4.当得到一个正确解时,在栈回退到上一个栈时,就会开始回溯,即将第一个皇后,放到第一列的所有正确解,全部得到.
5.然后回头继续第一个皇后放第二列,后面继续循环执行 1,2,3,4的步骤 * * *///定义一个max表示共有多少啊个皇后
const max = 8;
//定义数组array,保存皇后放置位置的结果,arr的index表示行,arr[index]值表示列,比如arr = {0,4,7,5,2,6,1,3},
//比如第二个皇后的坐标为第二行第四列
let array = new Array(max), step = 0, resultArr = [];
let array2 = new Array(max), step2 = 0, resultArr2 = [];//测试八皇后是否正确
check(0);
console.log('步数:', step);
console.log('解法数组:', resultArr);
check2();
console.log('步数2:', step2);
console.log(resultArr2)//编写一个方法,放置第n个皇后
function check(n) {if (n === max) { // n=8,其实八个皇后就已经放好了resultArr.push([...array])return}//依次放入皇后,并判断是否冲突for (let i = 0; i < max; i++) {//先把当前这个皇后n,放在该行的第1列array[n] = i;//统计步数step++;//判断当放置第n个皇后到i列时,是否冲突if (judge(n)) {//不冲突//接着放第n+1个皇后,即开始递归check(n + 1)}//如果冲突,就继续执行array[n] = i;即将第n个皇后,放置在本行的后移的一个位置}
}//第二种写法,使用for循环遍历完成
//八层for循环
function check2() {for (let a = 0; a < 8; a++) {array2[0] = a;step2++;if (!judge2(0)) {continue}for (let b = 0; b < 8; b++) {array2[1] = b;step2++;if (!judge2(1)) {continue}for (let c = 0; c < 8; c++) {array2[2] = c;step2++;if (!judge2(2)) {continue}for (let d = 0; d < 8; d++) {array2[3] = d;step2++;if (!judge2(3)) {continue}for (let e = 0; e < 8; e++) {array2[4] = e;step2++;if (!judge2(4)) {continue}for (let f = 0; f < 8; f++) {array2[5] = f;step2++;if (!judge2(5)) {continue}for (let g = 0; g < 8; g++) {array2[6] = g;step2++;if (!judge2(6)) {continue}for (let h = 0; h < 8; h++) {array2[7] = h;step2++;if (judge2(7)) {resultArr2.push([...array2])}}}}}}}}}
}//当我们放置第n个皇后,就去检测该皇后是否和前面已经摆放的皇后冲突
/*** * @param {表示第n个皇后} n */
function judge(n) {for (let i = 0; i < n; i++) {//1.array[i] == array[n] 表示判断第n个皇后是否和前面的n-1个皇后在同一列//2.Math.abs(n-i) === Math.abs(array[n] - array[i])表示在同一个斜线//n=1 放置第2列1 n=1 array[1] = 1// Math.abs(1-0) == 1 Math.abs(array[n] - array[i])=Math.abs(1-0) = 1//3.判断是否在同一行,没有必要,n每次都在递增if (array[i] === array[n] ||Math.abs(n - i) === Math.abs(array[n] - array[i])) {return false}}return true
}function judge2(n) {for (let i = 0; i < n; i++) {//1.array[i] == array[n] 表示判断第n个皇后是否和前面的n-1个皇后在同一列//2.Math.abs(n-i) === Math.abs(array[n] - array[i])表示在同一个斜线//n=1 放置第2列1 n=1 array[1] = 1// Math.abs(1-0) == 1 Math.abs(array[n] - array[i])=Math.abs(1-0) = 1//3.判断是否在同一行,没有必要,n每次都在递增if (array2[i] === array2[n] ||Math.abs(n - i) === Math.abs(array2[n] - array2[i])) {return false}}return true
}
测试: